将 DbContext 拆分为具有重叠 DbSet 的多个上下文
Splitting DbContext into multiple contexts with overlapping DbSets
我有一个 DbContext,目前包含 +80 个实体,只完成了 4 个主要模块,但还有 3 个要完成,而且它们相当大,所以很容易达到 150 个。我认为现在是划分上下文的最佳时机。每个模块都使用它自己的实体并将获得它自己的上下文,但是所有模块都使用一组实体,所以这里有一个问题:
我是否应该拥有一个包含所有重叠实体的 MainContext,然后:
- FK 依赖项会发生什么情况?
- 嵌套
using (var db = new context)
会有多大的性能问题,因为我需要从每个模块访问主上下文。
我是否应该将重叠的实体放在所有上下文中,但是
- 映射会发生什么情况,不会每个上下文都尝试映射它自己的实体并得到错误吗?
- 除了一个上下文之外,我是否应该排除所有重叠上下文的映射?
我应该留在一个上下文中吗?
还有其他建议吗?
如果您需要使用跨越多个 DbContext 的事务,您将遇到问题。无论是否所有的 DbContext 都连接到同一个数据库,它都会被提升为分布式事务。这让事情变得很慢。
您还将失去工作单元的好处,因为 DbContext 将独立跟踪它们的模型。
您仍然可以分离模型并复制共享模型。这不会导致不同的 DbContext 中断关系或死锁,超过两个人 运行 您的软件同时存在两个副本。
但是,为了使事情易于管理,您可以留在一个 DbContext 中,但隐藏每个模块中不需要的模型。
取下面的DbContext
-
public class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Vehicle> Cars { get; set; }
public DbSet<Trip> Trips { get; set; }
public DbSet<Company> Employers { get; set; }
public DbSet<Employee> Employees { get; set; }
}
如果你想做一个驾驶模块,你可能只用People, Cars, & Trips。如果您想要一个薪资模块,您可能只使用公司、员工和人员。所以你需要以下接口:
public interface IDrivingContext
{
DbSet<Person> People { get; }
DbSet<Vehicle> Cars { get; }
DbSet<Trip> Trips { get; }
}
public interface IPayrollContext
{
DbSet<Person> People { get; }
DbSet<Company> Employers { get; }
DbSet<Employee> Employees { get; }
}
然后您更改上下文以实现两个接口:
public class MyContext : DbContext, IDrivingContext, IPayrollContext
{
public DbSet<Person> People { get; set; }
public DbSet<Vehicle> Cars { get; set; }
public DbSet<Trip> Trips { get; set; }
public DbSet<Company> Employers { get; set; }
public DbSet<Employee> { get; set; }
}
并且当您使用 DbContext
时,只需将变量键入 IDrivingContext
或 IPayrollContext
,具体取决于您在哪个模块中编码:
using (IDrivingContext db = new MyDbContext())
{
// ...
}
using (IPayrollContext db = new MyDbContext())
{
// ...
}
我认为拆分上下文是个更好的主意。它使您有可能拥有更轻的上下文和更轻的上下文构建时间。此外,如果您对模块进行了更改,那么它不会影响整个数据库,例如您可以只部署应用程序的一部分。在不同的上下文中保持对象之间的关系是困难的。您可以在业务层处理此问题并将 Id 存储在数据库中。如果您不能以某种方式分离模型,那么我想您需要将它们放在一起。业务层是处理业务逻辑的地方,在那里你可以停止删除仍然链接的实体。然后数据库将处理数据库逻辑,例如:类型、大小、身份……我自己正在使用拆分上下文进行实验。从这里开始:
但是我的要复杂得多,并且还有重叠的实体,例如用户无处不在(创建者,修改者,...)
我有一个 DbContext,目前包含 +80 个实体,只完成了 4 个主要模块,但还有 3 个要完成,而且它们相当大,所以很容易达到 150 个。我认为现在是划分上下文的最佳时机。每个模块都使用它自己的实体并将获得它自己的上下文,但是所有模块都使用一组实体,所以这里有一个问题:
我是否应该拥有一个包含所有重叠实体的 MainContext,然后:
- FK 依赖项会发生什么情况?
- 嵌套
using (var db = new context)
会有多大的性能问题,因为我需要从每个模块访问主上下文。
我是否应该将重叠的实体放在所有上下文中,但是
- 映射会发生什么情况,不会每个上下文都尝试映射它自己的实体并得到错误吗?
- 除了一个上下文之外,我是否应该排除所有重叠上下文的映射?
我应该留在一个上下文中吗?
还有其他建议吗?
如果您需要使用跨越多个 DbContext 的事务,您将遇到问题。无论是否所有的 DbContext 都连接到同一个数据库,它都会被提升为分布式事务。这让事情变得很慢。
您还将失去工作单元的好处,因为 DbContext 将独立跟踪它们的模型。
您仍然可以分离模型并复制共享模型。这不会导致不同的 DbContext 中断关系或死锁,超过两个人 运行 您的软件同时存在两个副本。
但是,为了使事情易于管理,您可以留在一个 DbContext 中,但隐藏每个模块中不需要的模型。
取下面的DbContext
-
public class MyContext : DbContext
{
public DbSet<Person> People { get; set; }
public DbSet<Vehicle> Cars { get; set; }
public DbSet<Trip> Trips { get; set; }
public DbSet<Company> Employers { get; set; }
public DbSet<Employee> Employees { get; set; }
}
如果你想做一个驾驶模块,你可能只用People, Cars, & Trips。如果您想要一个薪资模块,您可能只使用公司、员工和人员。所以你需要以下接口:
public interface IDrivingContext
{
DbSet<Person> People { get; }
DbSet<Vehicle> Cars { get; }
DbSet<Trip> Trips { get; }
}
public interface IPayrollContext
{
DbSet<Person> People { get; }
DbSet<Company> Employers { get; }
DbSet<Employee> Employees { get; }
}
然后您更改上下文以实现两个接口:
public class MyContext : DbContext, IDrivingContext, IPayrollContext
{
public DbSet<Person> People { get; set; }
public DbSet<Vehicle> Cars { get; set; }
public DbSet<Trip> Trips { get; set; }
public DbSet<Company> Employers { get; set; }
public DbSet<Employee> { get; set; }
}
并且当您使用 DbContext
时,只需将变量键入 IDrivingContext
或 IPayrollContext
,具体取决于您在哪个模块中编码:
using (IDrivingContext db = new MyDbContext())
{
// ...
}
using (IPayrollContext db = new MyDbContext())
{
// ...
}
我认为拆分上下文是个更好的主意。它使您有可能拥有更轻的上下文和更轻的上下文构建时间。此外,如果您对模块进行了更改,那么它不会影响整个数据库,例如您可以只部署应用程序的一部分。在不同的上下文中保持对象之间的关系是困难的。您可以在业务层处理此问题并将 Id 存储在数据库中。如果您不能以某种方式分离模型,那么我想您需要将它们放在一起。业务层是处理业务逻辑的地方,在那里你可以停止删除仍然链接的实体。然后数据库将处理数据库逻辑,例如:类型、大小、身份……我自己正在使用拆分上下文进行实验。从这里开始: