My impression to date has been that a DbContext is meant to represent your database, and thus, if your application uses one database, you'd want only one DbContext. However, some colleagues want to break functional areas out into separate DbContext classes. I believe this comes from a good place -- a desire to keep the code cleaner -- but it seems volatile. My gut's telling me it's a bad idea, but unfortunately my gut feeling is not a sufficient condition for a design decision.
So I'm looking for A) concrete examples of why this might be a bad idea, or B) assurances that this'll all work out just fine.
In code first, you can have multiple DBContext and just one database. You just have to specify the connection string in the constructor.
Distinguishing contexts by setting the default schema
In EF6 you can have multiple contexts, just specify the name for the default database schema in the
OnModelCreating
method of youDbContext
derived class (where the Fluent-API configuration is). This will work in EF6:This example will use "Customer" as prefix for your database tables (instead of "dbo"). More importantly it will also prefix the
__MigrationHistory
table(s), e.g.Customer.__MigrationHistory
. So you can have more than one__MigrationHistory
table in a single database, one for each context. So the changes you make for one context will not mess with the other.When adding the migration, specify the fully qualified name of your configuration class (derived from
DbMigrationsConfiguration
) as parameter in theadd-migration
command:A short word on the context key
According to this MSDN article "Chapter - Multiple Models Targeting the Same Database" EF 6 would probably handle the situation even if only one
MigrationHistory
table existed, because in the table there is a ContextKey column to distinguish the migrations.However I prefer having more than one
MigrationHistory
table by specifying the default schema like explained above.Using separate migration folders
In such a scenario you might also want to work with different "Migration" folders in you project. You can set up your
DbMigrationsConfiguration
derived class accordingly using theMigrationsDirectory
property:Summary
All in all, you can say that everything is cleanly separated: Contexts, Migration folders in the project and tables in the database.
I would choose such a solution, if there are groups of entities which are part of a bigger topic, but are not related (via foreign keys) to one another.
If the groups of entities do not have anything to do which each other, I would created a separate database for each of them and also access them in different projects, probably with one single context in each project.
Inspired by [@JulieLerman 's DDD MSDN Mag Article 2013][1]
Reminder: If you do combine multiple contexts make sure you cut n paste all the functionality in your various
RealContexts.OnModelCreating()
into your singleCombinedContext.OnModelCreating()
.I just wasted time hunting down why my cascade delete relationships weren't being preserved only to discover that I hadn't ported the
modelBuilder.Entity<T>()....WillCascadeOnDelete();
code from my real context into my combined context.My gut told me the same thing when I came across this design.
I am working on a code base where there are three dbContexts to one database. 2 out of the 3 dbcontexts are dependent on information from 1 dbcontext because it serves up the administrative data. This design has placed constraints on how you can query your data. I ran into this problem where you cannot join across dbcontexts. Instead what you are required to do is query the two separate dbcontexts then do a join in memory or iterate through both to get the combination of the two as a result set. The problem with that is instead of querying for a specific result set you are now loading all your records into memory and then doing a join against the two result sets in memory. It can really slow things down.
I would ask the question "just because you can, should you?"
See this article for the problem I came across related to this design. The specified LINQ expression contains references to queries that are associated with different contexts
I'll weigh in against the idea, with real-world experience to back up my vote.
I was brought on to a large application that had five contexts for a single database. In the end, we ended up removing all of the contexts except for one - reverting back to a single context.
At first the idea of multiple contexts seems like a good idea. We can separate our data access into domains and provide several clean lightweight contexts. Sounds like DDD, right? This would simplify our data access. Another argument is for performance in that we only access the context that we need.
But in practice, as our application grew, many of our tables shared relationships across our various contexts. For example, queries to table A in context 1 also required joining table B in context 2.
This left us with a couple poor choices. We could duplicate the tables in the various contexts. We tried this. This created several mapping problems including an EF constraint that requires each entity to have a unique name. So we ended up with entities named Person1 and Person2 in the different contexts. One could argue this was poor design on our part, but despite our best efforts, this is how our application actually grew in the real world.
We also tried querying both contexts to get the data we needed. For example, our business logic would query half of what it needed from context 1 and the other half from context 2. This had some major issues. Instead of performing one query against a single context, we had to perform multiple queries across different contexts. This has a real performance penalty.
In the end, the good news is that it was easy to strip out the multiple contexts. The context is intended to be a lightweight object. So I don't think performance is a good argument for multiple contexts. In almost all cases, I believe a single context is simpler, less complex, and will likely perform better, and you won't have to implement a bunch of work-arounds to get it to work.
I thought of one situation where multiple contexts could be useful. A separate context could be used to fix a physical issue with the database in which it actually contains more than one domain. Ideally, a context would be one-to-one to a domain, which would be one-to-one to a database. In other words, if a set of tables are in no way related to the other tables in a given database, they should probably be pulled out into a separate database. I realize this isn't always practical. But if a set of tables are so different that you would feel comfortable separating them into a separate database (but you choose not to) then I could see the case for using a separate context, but only because there are actually two separate domains.
I'm interested in your thoughts.