21

我正在尝试将 EF 4.3 迁移与多个代码优先 DbContext 一起使用。我的应用程序分为几个插件,它们可能有自己的 DbContext 关于他们的域。应用程序应该使用一个单一的 sql 数据库。

当我尝试自动迁移空数据库中的上下文时,这只对第一个上下文成功。每个其他上下文都需要将 AutomaticMigrationDataLossAllowed-Property 设置为 true,然后尝试删除前一个的表。

所以我的问题是:

  • 我怎么能告诉迁移配置只是照顾在其相应上下文中定义的表而让所有其他人不理会?
  • 在单个数据库中通过自动迁移处理多个 DbContext 的正确工作流程是什么?

谢谢!

4

9 回答 9

32

这是你可以做的。非常简单。

您可以为每个上下文创建配置类。例如

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
   public Configuration1 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace1";
   }
}

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
   public Configuration2 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace2";
   }
}

现在添加迁移。您不需要启用迁移,因为您已经使用了上面的 2 类。

Add-Migration -configuration Configuration1 Context1Init

这将为 context1 创建迁移脚本。您可以对其他上下文再次重复此操作。

Add-Migration -configuration Configuration2 Context2Init

更新您的数据库

Update-Database -configuration Configuration1
Update-Database -configuration Configuration2

这可以按任何顺序完成。除非您需要确保按顺序调用每个配置。

于 2012-04-04T10:40:06.077 回答
6

Code First 迁移假设每个数据库只有一个迁移配置(每个配置一个上下文)。

我可以想到两种可能的解决方案:

  1. 创建一个包含每个上下文的所有实体的聚合上下文,并从您的迁移配置类中引用这个“超级”上下文。这样,所有表都将在用户的数据库中创建,但数据只会在他们安装了插件的表中。

  2. 为每个上下文使用单独的数据库。如果您在上下文之间共享实体,请添加自定义迁移并将CreateTable(...)调用替换为Sql("CREATE VIEW ...")从实体的“原始”数据库获取数据的调用。

我会尝试#1,因为它将所有内容都保存在一个数据库中。您可以在解决方案中创建一个单独的项目来包含您的迁移和这个“超级”上下文。只需添加项目,引用所有插件的项目,创建一个包含所有实体的上下文,然后在这个新项目上调用 Enable-Migrations。之后事情应该会按预期工作。

于 2012-02-10T20:36:32.773 回答
3

我有一个使用迁移的具有多个上下文的工作站点。但是,您确实需要为每个上下文使用一个单独的数据库,并且它都是由项目的 Migrations 命名空间中的 *Configuration 类驱动的,例如,CompanyDbContext 使用 CompanyConfiguration 指向 Company.sdf。update-database -configurationtypename CompanyConfiguration. 另一个 LogDbContext 使用 LogConfiguration 等指向 Log.sdf。

鉴于此工作,您是否尝试过创建 2 个指向同一数据库的上下文并告诉模型构建器忽略其他上下文的表列表?

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Ignore<OtherContextsClass>();
    // more of these
}

由于迁移与模型构建器一起使用,这可能会完成这项工作。

糟糕的替代方案是避免使用自动迁移,每次生成迁移,然后手动筛选并删除不需要的语句,然后运行它们,尽管没有什么能阻止您创建一个简单的工具来查看上下文和生成的语句并执行为您解决迁移问题。

于 2012-02-23T22:52:17.920 回答
1

好的,我已经为此苦苦挣扎了一天,这是寻求答案的人的解决方案...

我假设大多数阅读这篇文章的人都在这里,因为他们有一个带有很多 DbSet<> 属性的大型 DbContext 类,并且需要很长时间才能加载。您可能会想,哎呀,这很有意义,我应该拆分上下文,因为我不会一次使用所有 dbset,我只会根据需要的情况加载“部分”上下文它。因此,您将它们分开,却发现 Code First 迁移不支持您的革命性思维方式。

因此,您的第一步一定是拆分上下文,然后为每个新上下文添加了 MigrationConfiguration 类,添加了与新 Context 类命名完全相同的连接字符串。

然后,您尝试通过执行 Add-Migration Context1 然后执行 Update-Database -Verbose 来逐一运行新拆分的上下文...

一切似乎都运行良好,但随后您注意到每次后续迁移都删除了上一次迁移中的所有表,并且只留下了最后一次迁移中的表。

这是因为,当前的迁移模型要求每个数据库有一个 DbContext,并且它必须是镜像匹配。

我也尝试过,并且有人在这里建议这样做,是创建一个 SuperContext,其中包含所有 Db 集。创建一个单一的迁移配置类并在其中运行。保留部分上下文类,并尝试实例化并使用它们。EF 抱怨 Backing 模型发生了变化。同样,这是因为 EF 将您的部分 dbcontext 与您的 Super Context 迁移留下的 All-Sets 上下文签名进行比较。

这是我认为的一个重大缺陷。

就我而言,我认为性能比迁移更重要。所以,我最终做的是,在我在 Super 上下文中运行并准备好所有表之后,我进入数据库并手动删除了 _MigrationHistory 表。

现在,我可以在没有 EF 抱怨的情况下实例化和使用我的部分上下文。它没有找到 MigrationHistory 表,只是继续前进,使我能够获得数据库的“部分”视图。

当然,权衡是对模型的任何更改都必须手动传播到数据库,所以要小心。

不过它对我有用。

于 2012-05-27T03:19:22.123 回答
1

正如 Brice 上面提到的,最实用的解决方案是每个应用程序/数据库有 1 个超级 DbContext。

整个应用程序只能使用 1 个 DbContext 似乎是一个关键的技术和方法劣势,因为它会影响模块化等。此外,如果您使用 WCF 数据服务,则每个应用程序只能使用 1 个数据服务,因为数据服务只能映射到 1 个 DbContext。因此,这极大地改变了架构。

从好的方面来说,一个小的优势是所有与数据库相关的迁移代码都是集中的。

于 2012-11-10T02:20:54.327 回答
1

我刚刚遇到了这个问题,并意识到我将它们分成不同的上下文的原因纯粹是为了将相关模型分组到可管理的块中,而不是出于任何其他技术原因。相反,我已将我的上下文声明为部分类,现在具有不同模型的不同代码文件可以将 DbSet 添加到 DbContext。

这样,自动迁移魔法仍然有效。

于 2013-01-08T16:22:09.007 回答
0

我已经让它与手动迁移一起工作,但你不能降级,因为它不能区分 __MigrationHistory 表中的配置。如果我尝试降级,那么它会将来自其他配置的迁移视为自动迁移,并且由于我不允许数据丢失,它会失败。不过,我们只会使用它来升级,因此它适用于我们的目的。

虽然它看起来确实有点 ommision,但我相信只要 DbContexts 之间没有重叠,支持它就不难。

于 2012-05-03T09:13:57.490 回答
0

当然,解决方案应该是 EntityFramework 团队进行修改,以更改 API 以支持将 _MigrationHistory 表直接修改为您选择的表名,例如 _MigrationHistory_Context1 ,以便它可以处理独立 DbContext 实体的修改。这样一来,它们都被分开处理,并由开发人员确保实体的名称不会发生冲突。

似乎有很多人同意我的观点,即引用实体超集的重复 DbContext 是一种虚假的非企业友好的处理方式。对于基于模块化(Prism 或类似)的解决方案,重复的 DbContexts 惨遭失败。

于 2012-10-17T09:23:32.103 回答
0

我想让人们知道,下面的答案对我有用,但有一个警告:不要使用 MigrationsNamespace 行。

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
       public Configuration1 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace1";
   }
 }

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
   public Configuration2 (){
        AutomaticMigrationsEnabled = false;
        MigrationsNamespace = "YourProject.Models.ContextNamespace2";
   }
}

但是,我已经建立了 2 个数据库并定义了它们自己的上下文,所以我发现自己收到一条错误消息,提示“YourProject.Models 命名空间已经定义了 ContextNamespace1”。这是因为 "MigrationsNamespace = "YourProject.Models.ContextNamespace2";" 在我尝试 Init 之后,导致 dbcontext 在 YourProjects.Models 命名空间下定义了两次(一次在迁移 Context1Init 文件中,一次在我之前定义的位置)。

所以,我发现我当时必须做的是通过以下说明从头开始我的数据库和迁移(幸好我没有需要保留的数据):http: //pawel.sawicz.eu/entity -框架重置迁移/

然后我将代码更改为不包含 MigrationsNamespace 行。

internal sealed class Configuration1 : DbMigrationsConfiguration<Context1>{
       public Configuration1 (){
        AutomaticMigrationsEnabled = false;
   }
 }

internal sealed class Configuration2 : DbMigrationsConfiguration<Context2>{
   public Configuration2 (){
        AutomaticMigrationsEnabled = false;
   }
}

然后我再次运行 Add-Migration -configuration Configuration1 Context1Init 命令并再次运行 Update-Database -configuration Configuration1 行(对于我的第二个上下文),最后,现在一切似乎都很好。

于 2013-11-29T03:27:46.437 回答