Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Splitting DbContext into multiple contexts with overlapping DbSets

I have a DbContext that houses +80 entities at the moment with only 4 of the main modules done, but there are 3 more to go, and they are quite bigger so it will get up to 150 easy. I think it is the perfect time to divide the contexts. Every module uses it's own entities and will get it's own context, but there is a group of entities that are used by all of the modules, so here is mu question:

Should I have one MainContext that will have all of the overlapping entities but then:

  • What will happen to the FK dependencies?
  • How much of a performance issue would be to have nested using (var db = new context) because I will need to access the main context from every module.

Should I put the overlapping entities in all of the contexts, but then

  • What happens with the mapping, wouldn't every context try to map it's own entity and get an error?
  • Should I exclude the mapping of the overlapping contexts on all but one of the contexts?

Should I stay with one context?

Any other suggestions?

like image 543
GregoryHouseMD Avatar asked Jun 27 '15 09:06

GregoryHouseMD


1 Answers

You will have problems if you need to use a transaction that spans more than one DbContext. It will be promoted to a distributed transaction no matter if all of the DbContexts connect to the same database. This makes things very slow.

You will also lose the benefit of the unit of work because the DbContexts will track their models independently.

You could still separate the models and duplicate the shared ones. This will not cause the various DbContexts to break relationships or deadlock any more than two people running two copies of your software at the same time would.

However, to keep things manageable you can stay in one DbContext, but hide the models that are not needed in each module.

Take the following 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; }
}

If you wanted to make a driving module, you might only use People, Cars, & Trips. If you wanted a payroll module, you might only use Company, Employee, & People. So you would need the following interfaces:

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; }
}

Then you change your context to implement both interfaces:

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; }
}

And when you use the DbContext, only type the variable as IDrivingContext or IPayrollContext, depending on which module you are coding inside of:

using (IDrivingContext db = new MyDbContext())
{
     // ...
}

using (IPayrollContext db = new MyDbContext())
{
    // ...
}
like image 105
Keith Payne Avatar answered Oct 18 '22 13:10

Keith Payne