根据拆分 DbContext

Der*_*ğlu 1 c# entity-framework dbcontext .net-core

我想将我的DbContext班级分成几部分,以便每个模块都有自己的班级,我相信这会让工作更容易,更多的错误宝座并降低代码复杂性。

我相信我在过去的某个地方在谷歌搜索时看到过它,但没有找到它。

DbContext在基础设施层,我的类在域上下文中。那不是问题。我想将映射和配置分成单独的类。我的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);
    }

    ...
}
}
Run Code Online (Sandbox Code Playgroud)

我不知道拆分 DbContext 的确切方法。我需要一种方法来做到这一点。你能为我提供解决方案吗?

Sef*_*efe 6

您首先要清楚拆分DbContext. 你说这是一个关注点分离的问题,所以你应该首先决定要分离哪些关注点。在DbContext处理数据库表映射到一个对象模型,因此它的关注是有道理的,它涉及到的一切。关注点分离的另一端是不要将关注点拆分为多个部分,因为这也会增加程序的复杂性。

一个好的关注点分离是将它们DbContext放在一起,让它完成将数据库映射到对象模型的基本工作。额外的任务,比如对数据库的专门查询,将被封装在使用 的存储库中DbContext,这也允许您从实际的实体框架实现中抽象出您的业务层。

最重要的是,您仍然可以通过一些方法将您的“拆分”DbContext为多个部分:

制作DbContext一个部分类

您可以创建WestCoreDbContext一个分部类并将其内容拆分到多个代码文件中。您应该清楚编译后的输出将完全相同,因此您并没有真正改善 OOP 意义上的关注点分离。您还可以争论如果没有充分理由(例如部分自动生成的类)将单个类拆分为多个代码文件实际上会增加或减少代码的可管理性。这是您必须为自己做出的决定。

使用实体类型配置类

您可以使用 fluent API 使用派生自EntityTypeConfiguration(或在 .net Core 2.0 中实现IEntityTypeConfiguration接口)的类来配置实体类,这使您可以在 .net Core 2.0 之外配置实体类DbContext。当您拥有大量实体类时,这实际上有助于可管理性,其中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");
    }
}
Run Code Online (Sandbox Code Playgroud)

如果您使用的不是 .net Core 2.0,请查看此问答以获得相同的结果。