迁移和需要数据库的服务?

时间:2017-11-09 02:21:48

标签: c# entity-framework asp.net-core entity-framework-core

如果迁移工具"dotnet ef database update"在创建数据库之前运行我的应用程序BuildWebHost,如何在使用迁移的同时构建需要访问我的数据库的服务?尝试配置需要数据库的服务会引发异常,因为数据库不存在并导致迁移命令失败。因此永远不会创建数据库。

我使用的是asp.net core 2和EF Core 2。

更具体地说,使用空白数据库运行"dotnet ef database update"失败,并显示以下错误:

  

调用方法时遇到错误' BuildWebHost'在课堂上   '计划'。在没有应用服务提供商的情况下继续。错误:   无法打开数据库" MyDb"登录请求。登录失败。   用户' MYCOMPUTER \ MYNAME'。

登录失败

这是因为我已经构建了一个由我的" MyDb"支持的自定义配置提供程序。数据库(最终目标是使用自定义选项类绑定它)根据Microsoft Configuration Tutorial我的program.cs看起来像:

 public static IWebHost BuildWebHost(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((builderContext, config) =>
                {
                    var tmpconfig = config.Build();
                    config.AddMyOptionsConfig(options => options.UseSqlServer(tmpconfig.GetConnectionString("My_Database")));
                })
            .UseStartup<Startup>()
            .Build();

并且AddMyOptionsConfig最终运行:

  public class EFConfigProvider : ConfigurationProvider
    {
     [...]

        // Load config data from EF DB.
        public override void Load()
        {
            var builder = new DbContextOptionsBuilder<MyDbContext>();
            OptionsAction(builder);

            using (var dbContext = new MyDbContext(builder.Options))
            {    
                 // dbContext.Database.EnsureCreated(); // will cause first migration to fail
                 Data = !dbContext.ConfigurationValue.Any() // throws exception
                      ? CreateAndSaveDefaultValues(dbContext)
                      : dbContext.ConfigurationValue.ToDictionary(c => c.Id, c => c.Value);

在尝试访问数据库时抛出SQLException,因为尚未创建数据库。

但是,如果我尝试使用dbContext.Database.EnsureCreated(),则初始迁移将失败,因为表已存在。我想过尝试dbContext.Database.Migrate(),但作为初学者,我担心可能会对生产环境产生意想不到的后果。因此,我更喜欢通过命令行工具控制迁移。

从根本上说,问题似乎是"dotnet ef database update"运行应用程序启动 - BuildWebHost - 在创建数据库之前,但BuildWebHost中添加的自定义配置提供程序需要数据库已经存在

我该如何解决这个难题?

3 个答案:

答案 0 :(得分:0)

从某种意义上说,您已创建了循环引用。在ASP.NET Core项目上运行迁移时,将初始化应用程序以实例化运行迁移所需的DbContext。这是因为EF Core中的DbContext现在需要注入一个DbContextOptions实例,而不是EF中的旧方式,其中连接字符串名称(或实际完整)连接字符串)将直接在构造函数上定义。

通常,这可以正常工作,但是,正如您已经注意到的那样,因为应用程序初始化本身需要一个已经存在的数据库,所以在迁移之前无法运行它。因此,您有两种选择:

  1. 您可以尝试抽象需要现有数据库的部分。这可能就像将它包装在try-catch中并吞下异常或更复杂一样简单。由于迁移部分不需要此特定功能,因此可以安全地从该场景中的应用程序初始化中排除。

  2. 您可以将上下文和实体移动到类库中并实现IDesignTimeDbContextFactory以满足构建要迁移的DbContext的能力。然后,您将针对此类库而不是ASP.NET Core项目运行迁移。然后,回避了必须初始化应用程序以进行迁移的问题。

答案 1 :(得分:0)

BuildWebHost(和Startup.Configure)不应该用于应用程序启动逻辑。 ASP.NET团队的指导是使用Program.Main代替。

答案 2 :(得分:0)

到目前为止,我的解决方案是将支持自定义配置提供程序的实体移动到单独的dbContext中。

现在可以在需要时通过MyDbOptionsContext.Database.EnsureCreated()创建表而不影响迁移,因为它们基于主要上下文(MyDbContext)。

选项表不再参与迁移,但因为它不太可能改变,所以应该没有问题。另一个缺点是需要(由于有两个上下文)来明确指定dotnet ef命令行工具的上下文。