到目前为止,我的印象是DbContext是用来表示数据库的,因此,如果您的应用程序使用一个数据库,那么您只需要一个DbContext。
然而,一些同事希望将功能区域分解为单独的DbContext类。
我相信这是出于一个好的原因——希望保持代码更干净——但它似乎不稳定。我的直觉告诉我这是个坏主意,但不幸的是,我的直觉并不是设计决策的充分条件。
所以我在寻找:
A)为什么这可能是一个坏主意的具体例子;
B)保证这一切都会顺利解决。
到目前为止,我的印象是DbContext是用来表示数据库的,因此,如果您的应用程序使用一个数据库,那么您只需要一个DbContext。
然而,一些同事希望将功能区域分解为单独的DbContext类。
我相信这是出于一个好的原因——希望保持代码更干净——但它似乎不稳定。我的直觉告诉我这是个坏主意,但不幸的是,我的直觉并不是设计决策的充分条件。
所以我在寻找:
A)为什么这可能是一个坏主意的具体例子;
B)保证这一切都会顺利解决。
当前回答
灵感来自@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。莱托
其他回答
另一点“智慧”。我有一个面向互联网和内部应用程序的数据库。每一个面向都有一个上下文。这有助于我保持纪律严明的隔离。
首先,在代码中,可以有多个DBContext和一个数据库。您只需在构造函数中指定连接字符串。
public class MovieDBContext : DbContext
{
public MovieDBContext()
: base("DefaultConnection")
{
}
public DbSet<Movie> Movies { get; set; }
}
My gut told me the same thing when I came across this design. I am working on a code base where there are three dbContexts to one database. 2 out of the 3 dbcontexts are dependent on information from 1 dbcontext because it serves up the administrative data. This design has placed constraints on how you can query your data. I ran into this problem where you cannot join across dbcontexts. Instead what you are required to do is query the two separate dbcontexts then do a join in memory or iterate through both to get the combination of the two as a result set. The problem with that is instead of querying for a specific result set you are now loading all your records into memory and then doing a join against the two result sets in memory. It can really slow things down. I would ask the question "just because you can, should you?" See this article for the problem I came across related to this design. The specified LINQ expression contains references to queries that are associated with different contexts
我想分享一个案例,我认为在同一个数据库中有多个dbcontext的可能性是很有意义的。
我有一个解决方案与两个数据库。一个是除用户信息外的域数据。另一个仅用于用户信息。这一划分主要是由欧盟通用数据保护条例推动的。通过拥有两个数据库,我可以自由地移动域数据(例如,从Azure移动到我的开发环境),只要用户数据保持在一个安全的地方。
现在,对于用户数据库,我已经通过EF实现了两个模式。一个是AspNet身份框架提供的默认身份。另一个是我们自己实现任何与用户相关的东西。与扩展ApsNet模式相比,我更喜欢这种解决方案,因为我可以轻松地处理未来对AspNet身份的更改,同时这种分离使程序员清楚地知道,“我们自己的用户信息”应该放在我们定义的特定用户模式中。
通过设置默认模式来区分上下文
在EF6中,您可以有多个上下文,只需在DbContext派生类的OnModelCreating方法中指定默认数据库模式的名称(其中有Fluent-API配置)。 这将在EF6工作:
public partial class CustomerModel : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.HasDefaultSchema("Customer");
// Fluent API configuration
}
}
本例将使用“Customer”作为数据库表的前缀(而不是“dbo”)。 更重要的是,它还将作为__MigrationHistory表的前缀,例如Customer.__MigrationHistory。 因此,在一个数据库中可以有多个__MigrationHistory表,每个上下文对应一个。 因此,对一个上下文所做的更改不会影响到另一个上下文。
添加迁移时,在add-migration命令中指定配置类的全限定名称(派生自DbMigrationsConfiguration)作为参数:
add-migration NAME_OF_MIGRATION -ConfigurationTypeName FULLY_QUALIFIED_NAME_OF_CONFIGURATION_CLASS
上下文键上的一个简短的单词
根据这篇MSDN文章“章节-多个模型针对同一个数据库”,EF 6可能会处理这种情况,即使只有一个MigrationHistory表存在,因为在表中有一个ContextKey列来区分迁移。
但是,我更喜欢通过指定如上所述的默认模式来拥有多个MigrationHistory表。
使用单独的迁移文件夹
在这种情况下,您可能还想在项目中使用不同的“Migration”文件夹。你可以使用MigrationsDirectory属性设置你的DbMigrationsConfiguration派生类:
internal sealed class ConfigurationA : DbMigrationsConfiguration<ModelA>
{
public ConfigurationA()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = @"Migrations\ModelA";
}
}
internal sealed class ConfigurationB : DbMigrationsConfiguration<ModelB>
{
public ConfigurationB()
{
AutomaticMigrationsEnabled = false;
MigrationsDirectory = @"Migrations\ModelB";
}
}
总结
总而言之,您可以说所有内容都被清晰地分离了:项目中的上下文、迁移文件夹和数据库中的表。
我会选择这样的解决方案,如果有一组实体是一个更大的主题的一部分,但彼此不相关(通过外键)。
如果实体组之间没有任何关联,我会为它们每个创建一个单独的数据库,并在不同的项目中访问它们,可能每个项目中都有一个上下文。