2012-02-02 65 views
21

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

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

所以我的问题是:

  • 我怎么能告诉迁移的配置只是为了看看他们相应的上下文中定义的表后,独自离开所有其他人?
  • 在单个数据库中使用自动迁移处理多个DbContext的正确工作流程是什么?

谢谢!

+0

这是一个非常有趣的问题。我想知道是否有多个上下文支持是移植用例的一部分。 – 2012-02-02 19:31:45

+2

我非常怀疑多上下文可以使用自动迁移,它旨在更新数据库以使其看起来像上下文无论如何。您可能有更多的运气使用手动迁移来开发插件,针对单独的数据库生成迁移,然后将它们全部应用于相同的数据库。 – Betty 2012-02-04 02:11:28

+0

与此同时,我偷看了EF 4.3程序集,并且我也怀疑迁移框架能够应对多种情况。但是我没有想到的技术原因。使用EDM模型,您可以将其与数据库进行比较,找到现有表格表创建或更改,并通过手动迁移给用户保留删除方案。 – 2012-02-05 11:39:53

回答

6

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

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

  1. 创建聚合背景下,包括各个方面,并参考来自您的迁移配置类这种“超级”上下文的所有实体。这样所有的表格都将在用户的数据库中创建,但数据只会在他们安装插件的数据库中。

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

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

+5

我接受这个答案,不管它不是我的问题的答案。我认为将迁移设计为每个数据库只有一个上下文是一个错误。一方面,每个具有不在上下文中使用的表的遗留数据库都会产生问题。另一方面(即使预编译视图),具有大约100个不同实体的上下文的应用程序域需要很长时间才能开始。因此,将其分解为更小的上下文是目前唯一的解决方案。 – 2012-02-11 08:18:26

+3

我原来的答案已经变得有点过时了。 EF 6.0删除了每个数据库一个Code First上下文的限制。事情应该在6.0和更新的版本中“正常工作”。 – bricelam 2014-01-26 23:24:17

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 
} 

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

糟糕的选择是避免使用自动迁移,每次生成迁移,然后手动筛选并删除不需要的语句,然后运行它们,尽管没有任何东西阻止您创建一个查看上下文并生成的简单工具声明并为您执行迁移修复程序。

+1

谢谢你的答案。但不幸的是,我无法分割数据库。但是,你给了我一个很好的提示,即将自动化的输出作为手动输出的基础。 – 2012-02-24 07:36:22

+0

任何想法,如果它可以与多个模式(例如dbo)一起使用? – Betty 2012-02-26 08:27:35

32

这里是你可以做什么。很简单。

您可以为您的每一个方面的创造CONFIGRATION类。 例如

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 

这能够以任意顺序进行。除了你需要确保每次调用都是按顺序调用的。

+0

完美,它说“请指定要使用的一个”,我不知道该怎么做。谢谢! – joshcomley 2012-08-03 07:55:54

+1

当我尝试使用Context1 – 2013-01-09 14:43:48

+2

我得到“模型支持上下文已经改变”这应该被标记为答案!非常感谢! 为了防止在MVC 5和EF 6 – oskar132 2013-10-02 01:20:28

0

我知道了有手动迁移工作,但你不能降级,因为它不能在__MigrationHistory表配置之间discrimitate。如果我尝试降级,那么它会将来自其他配置的迁移视为自动并且因为我不允许数据丢失而失败。我们只会使用它来升级,因此它适用于我们的目的。

它看起来颇有几分ommision不过,我敢肯定它不会很难支持它提供有DbContexts之间没有重叠。

1

好吧,我一直在努力与这一天,这里是为那些寻求答案的解决方案...

我假设大多数人阅读这篇文章在这里是因为他们有一个大的DbContext类有很多DbSet <>属性,加载需要很长时间。你可能想过给自己,哎呀,这是有道理的,我应该分裂的背景下,因为我不会使用所有dbsets的一次,我只会根据我需要的情况下加载“部分”上下文它。所以你把它们分开,只是为了发现Code First迁移不支持你的革命思维方式。

因此,您的第一步必须分割上下文,然后为每个新上下文添加MigrationConfiguration类,您添加了与新的上下文类完全相同的连接字符串。

于是你试着运行一个新分裂上下文的一,通过做添加迁移CONTEXT1然后做更新,数据库-Verbose ...

一切似乎都做工精细,但后来你发现,每一个后续迁移从先前的迁移中删除了所有表,并且只从最后一次迁移中留下表。

这是因为,目前的迁移模型预计每个数据库单的DbContext,它必须是一个镜子比赛。

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

这是我认为的一个主要缺陷。

就我而言,我决定PERFORMANCE比迁移更重要。所以,我最终做的是,在我运行超级上下文并拥有所有表格后,我进入数据库并手动删除_MigrationHistory表。

现在,我可以实例化并使用我的部分上下文,而不用EF抱怨它。它没有找到MigrationHistory表,只是继续前进,让我有一个数据库的“部分”视图。

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

它虽然为我工作。

0

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

似乎有很多人分享我的观点,认为重复的DbContext与对实体超集的引用是一种虚假的非企业友好方式。对于基于模块化(棱镜或类似)的解决方案,重复的DbContext失败惨重。

1

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

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

另一方面,一个小优点是所有数据库相关的迁移代码都是集中的。

1

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

这种自动迁移法术仍然有效。

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(一次在迁移Context1Init文件中,一次在之前定义的位置)后,导致在YourProjects.Models命名空间下定义了dbcontext两次。

所以,我发现了我必须在这一点上做的是通过此处的指示,开始我的数据库,并从头开始迁移(幸好我没有数据,我需要保持): http://pawel.sawicz.eu/entity-framework-reseting-migrations/

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

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

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

然后我又跑加载迁移构型配置1 Context1Init命令,并再次更新,数据库构型配置1线(为我的第二个方面也是如此),最后,一切似乎是现在的工作很好。

相关问题