到目前为止,我的印象是DbContext是用来表示数据库的,因此,如果您的应用程序使用一个数据库,那么您只需要一个DbContext。
然而,一些同事希望将功能区域分解为单独的DbContext类。
我相信这是出于一个好的原因——希望保持代码更干净——但它似乎不稳定。我的直觉告诉我这是个坏主意,但不幸的是,我的直觉并不是设计决策的充分条件。
所以我在寻找:
A)为什么这可能是一个坏主意的具体例子;
B)保证这一切都会顺利解决。
到目前为止,我的印象是DbContext是用来表示数据库的,因此,如果您的应用程序使用一个数据库,那么您只需要一个DbContext。
然而,一些同事希望将功能区域分解为单独的DbContext类。
我相信这是出于一个好的原因——希望保持代码更干净——但它似乎不稳定。我的直觉告诉我这是个坏主意,但不幸的是,我的直觉并不是设计决策的充分条件。
所以我在寻找:
A)为什么这可能是一个坏主意的具体例子;
B)保证这一切都会顺利解决。
当前回答
提醒:如果你要组合多个上下文,请确保你在各种RealContexts.OnModelCreating()中剪切和粘贴所有功能到你的单个CombinedContext.OnModelCreating()。
我只是浪费时间寻找为什么我的级联删除关系没有被保存,却发现我没有移植modelBuilder.Entity<T>()....WillCascadeOnDelete();代码从我的真实上下文到我的组合上下文。
其他回答
另一点“智慧”。我有一个面向互联网和内部应用程序的数据库。每一个面向都有一个上下文。这有助于我保持纪律严明的隔离。
我想分享一个案例,我认为在同一个数据库中有多个dbcontext的可能性是很有意义的。
我有一个解决方案与两个数据库。一个是除用户信息外的域数据。另一个仅用于用户信息。这一划分主要是由欧盟通用数据保护条例推动的。通过拥有两个数据库,我可以自由地移动域数据(例如,从Azure移动到我的开发环境),只要用户数据保持在一个安全的地方。
现在,对于用户数据库,我已经通过EF实现了两个模式。一个是AspNet身份框架提供的默认身份。另一个是我们自己实现任何与用户相关的东西。与扩展ApsNet模式相比,我更喜欢这种解决方案,因为我可以轻松地处理未来对AspNet身份的更改,同时这种分离使程序员清楚地知道,“我们自己的用户信息”应该放在我们定义的特定用户模式中。
单个数据库可以有多个上下文。例如,如果您的数据库包含多个数据库模式,并且您希望将每个模式作为独立的自包含区域来处理,那么它就很有用。
问题是,当您想首先使用代码来创建数据库时,只有应用程序中的单个上下文可以做到这一点。这样做的技巧通常是一个额外的上下文,其中包含仅用于数据库创建的所有实体。仅包含实体子集的实际应用程序上下文必须将数据库初始化式设置为null。
在使用多种上下文类型时,还会遇到其他问题——例如共享实体类型及其从一个上下文传递到另一个上下文等等。一般来说,这是可能的,它可以使你的设计更干净,并分离不同的功能区域,但它的代价是额外的复杂性。
我四年前写了这个答案,我的观点一直没有改变。但自那以后,微服务领域有了重大发展。我在最后添加了特定的微服务注释……
我会权衡反对这个想法,用实际经验来支持我的投票。
我曾参与一个大型应用程序,该应用程序为单个数据库提供了五个上下文。最后,我们删除了所有的上下文,只有一个例外——返回到单个上下文。
起初,多重上下文的想法似乎是个好主意。我们可以将数据访问划分为域,并提供几个干净的轻量级上下文。听起来像DDD,对吧?这将简化我们的数据访问。另一个理由是为了性能,因为我们只访问我们需要的上下文。
但在实践中,随着应用程序的增长,许多表在各种上下文之间共享关系。例如,对上下文1中的表A的查询也需要连接上下文2中的表B。
这给我们留下了一些糟糕的选择。我们可以在不同的上下文中复制这些表。我们试过了。这产生了几个映射问题,包括一个EF约束,它要求每个实体都有唯一的名称。因此,我们在不同的上下文中得到了名为Person1和Person2的实体。有人可能会说这是我们糟糕的设计,但尽管我们尽了最大的努力,这就是我们的应用程序在现实世界中实际发展的方式。
我们还尝试查询两个上下文以获得所需的数据。例如,我们的业务逻辑将从上下文1查询所需内容的一半,从上下文2查询所需内容的另一半。这有一些主要的问题。我们必须跨不同的上下文执行多个查询,而不是针对单个上下文执行一个查询。这有一个真正的性能损失。
最后,好消息是很容易剥离出多个上下文。上下文是一个轻量级对象。所以我不认为性能在多种情况下都是一个很好的理由。在几乎所有情况下,我认为单个上下文更简单、更简单,而且可能性能更好,您不必实现一堆变通方法来让它工作。
I thought of one situation where multiple contexts could be useful. A separate context could be used to fix a physical issue with the database in which it actually contains more than one domain. Ideally, a context would be one-to-one to a domain, which would be one-to-one to a database. In other words, if a set of tables are in no way related to the other tables in a given database, they should probably be pulled out into a separate database. I realize this isn't always practical. But if a set of tables are so different that you would feel comfortable separating them into a separate database (but you choose not to) then I could see the case for using a separate context, but only because there are actually two separate domains.
对于微服务,单一的上下文仍然是有意义的。然而,对于微服务,每个服务都有自己的上下文,其中只包括与该服务相关的数据库表。换句话说,如果服务x访问表1和表2,服务y访问表3和表4,那么每个服务都有自己的唯一上下文,其中包含特定于该服务的表。
我对你的想法很感兴趣。
灵感来自@JulieLerman的DDD MSDN Mag文章2013
public class ShippingContext : BaseContext<ShippingContext>
{
public DbSet<Shipment> Shipments { get; set; }
public DbSet<Shipper> Shippers { get; set; }
public DbSet<OrderShippingDetail> Order { get; set; } //Orders table
public DbSet<ItemToBeShipped> ItemsToBeShipped { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Ignore<LineItem>();
modelBuilder.Ignore<Order>();
modelBuilder.Configurations.Add(new ShippingAddressMap());
}
}
public class BaseContext<TContext>
DbContext where TContext : DbContext
{
static BaseContext()
{
Database.SetInitializer<TContext>(null);
}
protected BaseContext() : base("DPSalesDatabase")
{}
}
如果你正在进行新的开发,你想让Code First基于你的类创建或迁移你的数据库,你将需要使用DbContext创建一个“超级模型”,其中包括构建一个表示数据库的完整模型所需的所有类和关系。但是,这个上下文不能继承自BaseContext。莱托