Reputation: 30625
I would like to split into pieces my DbContext
class so that each module has its own class which I believe makes working easier, more error throne and lowers code complexity.
I believe that I saw it somewhere in the past while googling however no luck of finding it.
My DbContext
is in Infrastructure Layer, and My classes are in Domain Context. That is not problem. I would like to separate mappings and configurations into separate classes. My DbContext
will remain same except it will be splitted.
I marked the code peaces I am willing to split into pieces below:
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);
}
...
}
}
I dont know exact way of splitting DbContext. I need a way for doing this. can you provide me solution?
Upvotes: 4
Views: 4141
Reputation: 49
You can use EF Core power tool and that will handle automatically.
Upvotes: 0
Reputation: 14007
You first have o be clear what you mean with split the DbContext
. You say that it is a separation of concerns issue, so you should first decide which concerns you want to separate. The DbContext
handles the concern of mapping the database table to an object model and so it makes sense that it does everything related to that. The other end of separation of concerns is to not split a concern into pieces since that too increases program complexity.
A good separation of concerns is to keep the DbContext
together and let it do the basic work of mapping the DB to your object model. Additional tasks, like specialized queries to the DB would be encapsualted in repositories that would use the DbContext
, which also allows you to abstract your business layer from the actual entity framework implementation.
On top of that there are still some ways you can "split" your DbContext
into pieces:
Make the DbContext
a partial class
You can make WestCoreDbContext
a partial class and split its contents over multiple code files. You should be clear though that the compiled output will be exactly the same, so you don't really improve separation of concerns in an OOP sense. You can also argue if splitting a single class to multiple code files without a good reason (like the class being partially auto-generated) will actually increase or decrease manageablity of your code. This is a decision you have to make for yourself.
Use entity type configuration classes
You can configure your entity classes with the fluent API using classes derived from EntityTypeConfiguration
(or implementing the IEntityTypeConfiguration
interface in .net Core 2.0), which let you to configure your entity classes outside the DbContext
. This can actually help manageability when you have a larger amount of entity classes, where the OnModelCreating
method would become very long.
In your case this would look like this in .net Core 2.0 (I have simplified your example):
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");
}
}
If you are not on .net Core 2.0, check this Q&A to achieve the same result.
Upvotes: 10