我应该把Database.EnsureCreated放在哪里?(涉及IT技术)

11

我有一个使用Entity Framework Core和ASP.NET Core构建的应用程序,当我的应用程序启动时,我想确保数据库被创建,并且最终(一旦我拥有迁移),我也想确保这些迁移也被运行。

最初我将Database.EnsureCreated()放入我的DbContext的构造函数中,但由于每次创建DbContext的新实例时都会运行该代码,因此显然每次有人访问我的应用程序时都会运行它。

我试图将它放入我的启动代码中,但我需要一个DbContext的实例才能这样做,而如何获取一个实例并不清楚。 我正在进行以下EF配置:


serviceCollection.AddEntityFramework()
    .AddSqlServer()
    .AddDbContext<Models.MyContext>(options => options.UseSqlServer(...));

我不知道如何从服务集合中获取DbContext的实例,并且我也没有看到适当的单例可以注入DbContext,以便我可以进行一次性初始化。

那么最好的地方是什么,以确保与我的DbContext相关的某些代码在每次应用程序运行时只被调用一次?


EnsureCreated 方法仅用于测试,不适用于生产环境。 - ErikEJ
3个回答

6

截至目前,还没有一个“正确”的位置可以在应用程序启动时运行代码,使其在请求范围内执行(请参见https://github.com/aspnet/Hosting/issues/373)。

目前的解决方法是进行以下操作,但在更复杂的多应用程序场景中将无法使用(请参见https://github.com/aspnet/EntityFramework/issues/3070#issuecomment-142752126)。

public class Startup
{
    ...

    public void Configure(IApplicationBuilder applicationBuilder, ...)
    {
        ...
        // NOTE: this must go at the end of Configure
        var serviceScopeFactory = applicationBuilder.ApplicationServices.GetRequiredService<IServiceScopeFactory>()
        using (var serviceScope = serviceScopeFactory.CreateScope())
        {
            var dbContext = serviceScope.ServiceProvider.GetService<MyDbContext>();
            dbContext.Database.EnsureCreated();
        }
    }
}

嗨,Micah,我同意你的看法,因为我也看到了GitHub上的3070号问题,但是你不能直接将MyDbContext注入到你的Configure()方法中吗? - Nate Anderson
1
我相信我刚刚从那个GitHub问题中复制了这个。可能有更好的方法,但我假设那个作者(作为EF开发人员)知道什么是最好的,所以我只是复制了他们的解决方案。Configure在DI初始化之前还是之后运行?也许你从serviceScopeFactory得到的dbContext与你从DI得到的不同?如果你找到比这更好的解决方案,请随时在这里提交编辑或评论。 :) - Micah Zoltu
只是检查一下,我也对这个话题不了解 :) 我在至少两个地方回答过(示例),声称将 DI 直接注入到 Configure() 中是 intro docs 的做法,也许有人会告诉我为什么我错了,或者他们的做法有何不同。谢谢。 - Nate Anderson
我不知道这是否适用于早期版本,对我来说它说 DI 容器中找不到 MyDbContext。我认为这是在 ConfigureServices 之前执行的,或者是并行执行的。 - Lee Song

4
我想知道为什么您会在服务的一部分中运行EnsureCreated。 您是否真的想让您的Web服务器创建或更新数据库架构?如果数据库不是最新状态,为什么Web服务器会启动并提供请求呢?
您真的非常信任迁移吗?它们在执行时不会破坏数据,您不想在运行它们后测试数据吗?
此外,这将要求您向Web服务器数据库用户授予更改数据库模式的权限。这本身就是一个漏洞 - 接管您的Web服务器的人将能够修改您的数据库模式。
我建议您在自己运行的小型实用程序中创建数据库并应用迁移,而不是作为Web应用程序的一部分。

我很欣赏你对于在应用程序内部创建/迁移的反对意见。对于企业级应用程序,我倾向于在所有方面都同意您的观点。然而,对于小型初创服务来说,在应用程序内部进行创建/迁移大大简化了部署、测试、迁移、管理、调试等工作,我认为这是值得冒险的,特别是在努力实现MVP时。一旦服务发展足够成熟,就可以考虑提取出DB的创建/迁移。 - Micah Zoltu
在我的情况下,我的客户是一位基于Linux的程序员,他希望通过编辑配置文件来切换数据库服务器。他将处理克隆等操作。如果没有EnsureCreated,他必须安装所有工具才能运行Update-Database。 - Lee Song
有一个很好的“迁移”实用程序可以做到这一点。 - zmbq
在使用内存数据库或测试期间,这是开发中可以使用的完全有效的东西。 - Douglas Gaskell

0

我认为zmbq的建议是正确的,确保迁移与部署同时运行,以便二进制文件和数据库更改同步使用Visual Studio的发布功能。

当发布到IIS实例时,可以指定目标数据库连接字符串以运行所需的迁移:

Entity framework migrations used when publishing

这将确保仅在需要时(而不是每次应用程序启动时)应用更改,并且应用程序使用最少所需的数据库权限(即数据库编写器、阅读器等),而不是更改表、创建索引等权限。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接