拆分 DbContext 根据
Splitting DbContext according to
我想将我的 DbContext
class 拆分成多个部分,以便每个模块都有自己的 class,我相信这可以使工作更轻松、错误率更高并降低代码复杂性。
我相信我在谷歌搜索时曾在某个地方看到过它,但没有找到它。
我的 DbContext
在基础设施层,我的 class 在域上下文中。那不是问题。我想将映射和配置分离到单独的 classes 中。我的 DbContext
将保持不变,只是它会被拆分。
我在下面标记了我愿意拆分的代码:
public class WestCoreDbContext : DbContext
{
public WestCoreDbContext(DbContextOptions<WestCoreDbContext> options) : base(options)
{
}
#region WOULD LIKE TO SPLIT THIS PART
public virtual DbSet<SoftwareTest> SoftwareTests { get; set; }
public virtual DbSet<SoftwareTestCase> SoftwareTestCases { get; set; }
public virtual DbSet<SoftwareTestCaseStep> SoftwareTestCaseSteps { get; set; }
public virtual DbSet<SoftwareTestCaseStepResult> SoftwareTestCaseStepResults { get; set; }
public virtual DbSet<Position> Positions { get; set; }
#endregion
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region WOULD LIKE TO SPLIT THIS PART
SoftwareTestMapping(modelBuilder);
SoftwareTestCaseMapping(modelBuilder);
SoftwareTestCaseMapping(modelBuilder);
SoftwareTestCaseStepMapping(modelBuilder);
SoftwareTestCaseStepResultsMapping(modelBuilder);
PositionMapping(modelBuilder);
RelationshipsMapping(modelBuilder);
#endregion
modelBuilder.MyOracleNamingConventions();
base.OnModelCreating(modelBuilder);
}
#region WOULD LIKE TO SPLIT THIS PART
private void SoftwareTestMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTest>();
}
private void SoftwareTestCaseMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTestCase>();
}
private void SoftwareTestCaseStepMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTestCaseStep>();
}
private void PositionMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Position>();
}
private void SoftwareTestCaseStepResultsMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTestCaseStepResult>();
}
private void RelationshipsMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTest>().HasMany(x => x.SoftwareTestCases).WithOne(op => op.SoftwareTest).IsRequired().HasForeignKey(@"StId");
modelBuilder.Entity<SoftwareTestCase>().HasOne(x => x.SoftwareTest).WithMany(op => op.SoftwareTestCases).IsRequired().HasForeignKey(@"StId");
modelBuilder.Entity<SoftwareTestCase>().HasMany(x => x.SoftwareTestCaseSteps).WithOne(op => op.SoftwareTestCase).IsRequired().HasForeignKey("StcId");
modelBuilder.Entity<SoftwareTestCaseStep>().HasOne(x => x.SoftwareTestCase).WithMany(op => op.SoftwareTestCaseSteps).IsRequired().HasForeignKey("StcId");
modelBuilder.Entity<SoftwareTestCaseStep>().HasMany(x => x.SoftwareTestCaseStepResults).WithOne(op => op.SoftwareTestCaseStep).IsRequired().HasForeignKey("StcsId");
modelBuilder.Entity<SoftwareTestCaseStepResult>().HasOne(x => x.SoftwareTestCaseStep).WithMany(op => op.SoftwareTestCaseStepResults).IsRequired().HasForeignKey("StcsId");
}
#endregion
public bool HasChanges()
{
return ChangeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted);
}
...
}
}
我不知道拆分 DbContext 的确切方法。
我需要一种方法来做到这一点。你能给我解决方案吗?
你首先要清楚拆分 DbContext
是什么意思。您说这是关注点分离问题,因此您应该首先确定要分离哪些关注点。 DbContext
处理将数据库 table 映射到对象模型的问题,因此它做与此相关的所有事情是有道理的。关注点分离的另一端是不要将关注点拆分成多个部分,因为这也会增加程序的复杂性。
一个很好的关注点分离是将 DbContext
放在一起,让它完成将数据库映射到对象模型的基本工作。额外的任务,比如对数据库的专门查询将被封装在使用 DbContext
的存储库中,这也允许您从实际的 entity framework 实现中抽象出您的业务层。
除此之外,还有一些方法可以 "split" 您的 DbContext
成碎片:
将 DbContext
设为部分 class
您可以将 WestCoreDbContext
设为 partial class 并将其内容拆分为多个代码文件。尽管编译后的输出将完全相同,但您应该清楚,因此您并没有真正改进 OOP 意义上的关注点分离。您还可以争辩说,如果没有充分的理由(例如 class 是部分自动生成的)将单个 class 拆分为多个代码文件是否实际上会增加或减少代码的可管理性。这是你必须自己做出的决定。
使用实体类型配置classes
您可以使用从 .net Core 2.0 中的 EntityTypeConfiguration
(or implementing the IEntityTypeConfiguration
interface 派生的 classes 使用流畅的 API 配置您的实体 classes,这让您可以配置您的实体 class 在 DbContext
之外。当您拥有大量实体 classes 时,这实际上有助于提高可管理性,其中 OnModelCreating
方法会变得很长。
在你的情况下,这在 .net Core 2.0 中看起来像这样(我已经简化了你的示例):
public class WestCoreDbContext : DbContext
{
public WestCoreDbContext(DbContextOptions<WestCoreDbContext> options) : base(options)
{
}
public virtual DbSet<SoftwareTestCase> SoftwareTestCases { get; set; }
//Define further DbSets
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new SoftwareTestCaseConfiguration());
//Apply further configurations
modelBuilder.MyOracleNamingConventions();
base.OnModelCreating(modelBuilder);
}
public bool HasChanges()
{
return ChangeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted);
}
}
//This configuration class is separated from the WestCoreDbContext and can go into a separate code file
internal class SoftwareTestCaseConfiguration : IEntityTypeConfiguration<SoftwareTestCase>
{
public void Configure(EntityTypeBuilder<SoftwareTestCase> modelBuilder)
{
modelBuilder.Entity<SoftwareTestCase>().HasOne(x => x.SoftwareTest).WithMany(op => op.SoftwareTestCases).IsRequired().HasForeignKey(@"StId");
modelBuilder.Entity<SoftwareTestCase>().HasMany(x => x.SoftwareTestCaseSteps).WithOne(op => op.SoftwareTestCase).IsRequired().HasForeignKey("StcId");
}
}
如果您使用的不是 .net Core 2.0,请检查 this Q&A 以获得相同的结果。
您可以使用 EF Core 强大的工具,它会自动处理。
我想将我的 DbContext
class 拆分成多个部分,以便每个模块都有自己的 class,我相信这可以使工作更轻松、错误率更高并降低代码复杂性。
我相信我在谷歌搜索时曾在某个地方看到过它,但没有找到它。
我的 DbContext
在基础设施层,我的 class 在域上下文中。那不是问题。我想将映射和配置分离到单独的 classes 中。我的 DbContext
将保持不变,只是它会被拆分。
我在下面标记了我愿意拆分的代码:
public class WestCoreDbContext : DbContext
{
public WestCoreDbContext(DbContextOptions<WestCoreDbContext> options) : base(options)
{
}
#region WOULD LIKE TO SPLIT THIS PART
public virtual DbSet<SoftwareTest> SoftwareTests { get; set; }
public virtual DbSet<SoftwareTestCase> SoftwareTestCases { get; set; }
public virtual DbSet<SoftwareTestCaseStep> SoftwareTestCaseSteps { get; set; }
public virtual DbSet<SoftwareTestCaseStepResult> SoftwareTestCaseStepResults { get; set; }
public virtual DbSet<Position> Positions { get; set; }
#endregion
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
#region WOULD LIKE TO SPLIT THIS PART
SoftwareTestMapping(modelBuilder);
SoftwareTestCaseMapping(modelBuilder);
SoftwareTestCaseMapping(modelBuilder);
SoftwareTestCaseStepMapping(modelBuilder);
SoftwareTestCaseStepResultsMapping(modelBuilder);
PositionMapping(modelBuilder);
RelationshipsMapping(modelBuilder);
#endregion
modelBuilder.MyOracleNamingConventions();
base.OnModelCreating(modelBuilder);
}
#region WOULD LIKE TO SPLIT THIS PART
private void SoftwareTestMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTest>();
}
private void SoftwareTestCaseMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTestCase>();
}
private void SoftwareTestCaseStepMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTestCaseStep>();
}
private void PositionMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Position>();
}
private void SoftwareTestCaseStepResultsMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTestCaseStepResult>();
}
private void RelationshipsMapping(ModelBuilder modelBuilder)
{
modelBuilder.Entity<SoftwareTest>().HasMany(x => x.SoftwareTestCases).WithOne(op => op.SoftwareTest).IsRequired().HasForeignKey(@"StId");
modelBuilder.Entity<SoftwareTestCase>().HasOne(x => x.SoftwareTest).WithMany(op => op.SoftwareTestCases).IsRequired().HasForeignKey(@"StId");
modelBuilder.Entity<SoftwareTestCase>().HasMany(x => x.SoftwareTestCaseSteps).WithOne(op => op.SoftwareTestCase).IsRequired().HasForeignKey("StcId");
modelBuilder.Entity<SoftwareTestCaseStep>().HasOne(x => x.SoftwareTestCase).WithMany(op => op.SoftwareTestCaseSteps).IsRequired().HasForeignKey("StcId");
modelBuilder.Entity<SoftwareTestCaseStep>().HasMany(x => x.SoftwareTestCaseStepResults).WithOne(op => op.SoftwareTestCaseStep).IsRequired().HasForeignKey("StcsId");
modelBuilder.Entity<SoftwareTestCaseStepResult>().HasOne(x => x.SoftwareTestCaseStep).WithMany(op => op.SoftwareTestCaseStepResults).IsRequired().HasForeignKey("StcsId");
}
#endregion
public bool HasChanges()
{
return ChangeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted);
}
...
}
}
我不知道拆分 DbContext 的确切方法。 我需要一种方法来做到这一点。你能给我解决方案吗?
你首先要清楚拆分 DbContext
是什么意思。您说这是关注点分离问题,因此您应该首先确定要分离哪些关注点。 DbContext
处理将数据库 table 映射到对象模型的问题,因此它做与此相关的所有事情是有道理的。关注点分离的另一端是不要将关注点拆分成多个部分,因为这也会增加程序的复杂性。
一个很好的关注点分离是将 DbContext
放在一起,让它完成将数据库映射到对象模型的基本工作。额外的任务,比如对数据库的专门查询将被封装在使用 DbContext
的存储库中,这也允许您从实际的 entity framework 实现中抽象出您的业务层。
除此之外,还有一些方法可以 "split" 您的 DbContext
成碎片:
将 DbContext
设为部分 class
您可以将 WestCoreDbContext
设为 partial class 并将其内容拆分为多个代码文件。尽管编译后的输出将完全相同,但您应该清楚,因此您并没有真正改进 OOP 意义上的关注点分离。您还可以争辩说,如果没有充分的理由(例如 class 是部分自动生成的)将单个 class 拆分为多个代码文件是否实际上会增加或减少代码的可管理性。这是你必须自己做出的决定。
使用实体类型配置classes
您可以使用从 .net Core 2.0 中的 EntityTypeConfiguration
(or implementing the IEntityTypeConfiguration
interface 派生的 classes 使用流畅的 API 配置您的实体 classes,这让您可以配置您的实体 class 在 DbContext
之外。当您拥有大量实体 classes 时,这实际上有助于提高可管理性,其中 OnModelCreating
方法会变得很长。
在你的情况下,这在 .net Core 2.0 中看起来像这样(我已经简化了你的示例):
public class WestCoreDbContext : DbContext
{
public WestCoreDbContext(DbContextOptions<WestCoreDbContext> options) : base(options)
{
}
public virtual DbSet<SoftwareTestCase> SoftwareTestCases { get; set; }
//Define further DbSets
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.ApplyConfiguration(new SoftwareTestCaseConfiguration());
//Apply further configurations
modelBuilder.MyOracleNamingConventions();
base.OnModelCreating(modelBuilder);
}
public bool HasChanges()
{
return ChangeTracker.Entries().Any(e => e.State == EntityState.Added || e.State == EntityState.Modified || e.State == EntityState.Deleted);
}
}
//This configuration class is separated from the WestCoreDbContext and can go into a separate code file
internal class SoftwareTestCaseConfiguration : IEntityTypeConfiguration<SoftwareTestCase>
{
public void Configure(EntityTypeBuilder<SoftwareTestCase> modelBuilder)
{
modelBuilder.Entity<SoftwareTestCase>().HasOne(x => x.SoftwareTest).WithMany(op => op.SoftwareTestCases).IsRequired().HasForeignKey(@"StId");
modelBuilder.Entity<SoftwareTestCase>().HasMany(x => x.SoftwareTestCaseSteps).WithOne(op => op.SoftwareTestCase).IsRequired().HasForeignKey("StcId");
}
}
如果您使用的不是 .net Core 2.0,请检查 this Q&A 以获得相同的结果。
您可以使用 EF Core 强大的工具,它会自动处理。