EF Core创建和迁移数据库都非常方便,比EF6的体验更好。
虽然EF Core为我们提供了非常好用的ORM,但很多时候我们可能仍然需要使用存储过程。很遗憾的是,我没有在EF Core的文档中找到在创建数据库的同时创建存储过程的方法,只能在EF Core创建数据库后手动创建和更新存储过程,这在项目初始阶段搭建和验证数据结构时非常烦琐。因为这个阶段往往会反复修改和迁移数据库,为了保证数据库迁移历史的“干净“,通常迁移时都会删除数据库重新创建,这又不得不重新创建存储过程。
下面看看如何使用EF Core在项目启动时自动创建存储过程
在项目中添加一个目录:StoreProcedure,把创建存储过程的脚本添加到该目录下,可以保存为文本文件。注:如果保存为sql脚本文件(后缀名为sql),VS2017会用sql server的语法校验文件,我用的是mysql数据库,会出现很多语法错误提示。
选择这个脚本文件,打开“属性”面板,按照图示把“复制到输出目录”改为“如果较新则复制”,把“生成操作”改为“嵌入的资源”,当项目发布时,StoreProcedure目录和脚本文件就会发布到服务器上。

如果有多个存储过程,每个存储过程的脚本保存为单独一份文件,并且把“复制到输出目录”改为“如果较新则复制”,“生成操作”可以不变。实际上“生成操作”只要在首次发布时改为“嵌入的资源”就可以了,即使以后改为默认值“无”,也没关系,而且目录下只要有一份文件设置为“嵌入的资源”,该目录下的所有文件都会发布的服务器上。
存储过程脚本示例(MySql):
DROP PROCEDURE IF EXISTS `GetMembers`;
CREATE DEFINER=`root`@`%` PROCEDURE `GetMembers`()
BEGIN
SELECT * FROM Member;
END;
接下来添加一个新类:SeedData,在EF Core的教程中用这个类来进行数据初始化,我们把创建存储过程的方法也放到这个类中。
添加方法:
public static async Task CreateStoreProcedure(IServiceProvider serviceProvider)
{
//BowlContext是EF Core数据上下文
using (BowlContext context = new BowlContext(
serviceProvider.GetRequiredService<DbContextOptions<BowlContext>>()))
{
var path = $"{AppContext.BaseDirectory}StoreProcedure";
var files = Directory.GetFiles(path);
foreach(var filename in files)
{
string script = File.ReadAllText(filename);
await context.Database.ExecuteSqlCommandAsync(script);
}
}
}
代码很简单,读取StoreProcedure目录下所有文件,并将每个文件中的内容做为脚本在数据库中执行。
修改项目的Program.cs文件中的启动方法Main
public static void Main(string[] args)
{
var host = CreateWebHostBuilder(args).Build();
using (var scope = host.Services.CreateScope())
{
var service = scope.ServiceProvider;
try
{
var context = service.GetRequiredService<ShunShiContext>();
context.Database.Migrate();
//初始化数据
SeedData.Initialize(service).Wait();
//创建存储过程
SeedData.CreateStoreProcedure(service).Wait();
}
catch (Exception ex)
{
var logger = service.GetRequiredService<ILogger<Program>>();
logger.LogError(ex, "数据库初始化错误!");
}
}
host.Run();
}
在本地调试时,程序每次启动都会自动删除旧的存储过程,创建新的存储过程。发布后也会执行一次创建存储过程的代码。这就达到了自动创建和更新存储过程的目的。
如果觉得本地调试每次启动都会更新存储过程不太好的话,也可以修改一下CreateStoreProcedure方法,做到有条件更新,比如增加一个更新清单,只更新清单中列出的存储过程等等,方法很多,不再赘述了。
网友评论