Разделение DbContext в соответствии с

Я хотел бы разделить на части мой класс 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);
    }

    ...
}
}

Я не знаю точного способа разделения DbContext. Мне нужен способ сделать это. Вы можете предоставить мне решение?


person Derviş Kayımbaşıoğlu    schedule 13.12.2017    source источник
comment
Так в чем твой вопрос?   -  person DavidG    schedule 13.12.2017
comment
Я не уверен, как разделить DBContext на более мелкие части. Я хочу иметь 1 DbContext, но с меньшими частями. Для меня проблема разделения интересов.   -  person Derviş Kayımbaşıoğlu    schedule 13.12.2017
comment
Вы хоть пытались это сделать? Просто скопируйте этот класс, дайте ему новое имя и удалите ненужные биты.   -  person DavidG    schedule 13.12.2017
comment
кажется, вы пытаетесь сделать это в одном классе, который работает, но потребуется рефакторинг. Самый простой способ сделать это — иметь несколько классов DbContext, поскольку вы не можете сделать свойства недоступными внутри класса. Интерфейс может быть решением, если у вас есть минимальные рабочие требования. Однако обратите внимание, что этот подход вряд ли повлияет на сложность кода, а сохранение при построении модели может быть выполнено только с несколькими классами (если вы не хотите рефакторить свой BL, чтобы не использовать свойства DbSet).   -  person DevilSuichiro    schedule 13.12.2017
comment
Обратите внимание, что context.Set<T>() всегда будет предоставлять доступ ко всем отображаемым объектам в контексте. Это может быть один из тех редких случаев, когда оправдан дополнительный уровень абстракции Unit of Work/Generic Repository. Также обратите внимание, что скомпилированная модель, принадлежащая одному классу контекста, будет построена только один раз за время жизни приложения. Вы не можете скомпилировать модель для каждого экземпляра (ну, это возможно, но не рекомендуется). Поэтому, если это то, что вы подразумеваете под разделением, имейте в виду, что для этого вам нужны разные контекстные классы.   -  person Gert Arnold    schedule 13.12.2017


Ответы (1)


Сначала вы должны четко понимать, что вы имеете в виду под разделением DbContext. Вы говорите, что это вопрос разделения интересов, поэтому вам следует сначала решить, какие вопросы вы хотите разделить. DbContext занимается сопоставлением таблицы базы данных с объектной моделью, поэтому имеет смысл делать все, что с этим связано. Другая сторона разделения задач — не разбивать задачу на части, поскольку это также увеличивает сложность программы.

Хорошее разделение задач состоит в том, чтобы держать DbContext вместе и позволить ему выполнять основную работу по сопоставлению БД с вашей объектной моделью. Дополнительные задачи, такие как специализированные запросы к БД, будут инкапсулированы в репозитории, которые будут использовать DbContext, что также позволит вам абстрагироваться от вашего бизнес-уровня от фактической реализации инфраструктуры сущностей.

Кроме того, есть еще несколько способов, которыми вы можете «разделить» свой DbContext на части:

Сделайте DbContext разделяемым классом

Вы можете сделать WestCoreDbContext partial class и разделить его содержимое на несколько файлов кода. Однако вам должно быть ясно, что скомпилированный вывод будет точно таким же, поэтому вы на самом деле не улучшаете разделение задач в смысле ООП. Вы также можете утверждать, что разделение одного класса на несколько файлов кода без уважительной причины (например, частично автоматически сгенерированный класс) действительно увеличит или уменьшит управляемость вашего кода. Это решение вы должны принять сами.

Использовать классы конфигурации типов объектов

Вы можете настроить классы сущностей с помощью Fluent API, используя классы, производные от EntityTypeConfiguration. (или реализация интерфейса IEntityTypeConfiguration< /a> в .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");
    }
}

Если вы не используете .net Core 2.0, проверьте эти вопросы и ответы, чтобы получить тот же результат.

person Sefe    schedule 13.12.2017