efcore: Inheritance problem with DbContext subclasses requiring constructor to supply DbContextOptions
I am building web APIs in ASP.NET Core 1.1.
I have a number different databases (for different systems) which have common base schemas for configuration items such as Configuration, Users and groups (about 25 tables in all). I am trying to avoid duplicating the quite extensive EF model configuration for the shared part of the model by inheriting from a base class.
InvestContext BatchContext
^ ^
| |
_________________
|
ConfigurationContext
^
|
DbContext
However, this does not work because of the Entity Framework (EF) requirement to pass DbContextOptions<DerivedContext>
as a parameter to the constructor, where DerivedContext
must match the type of the context the constructor is called on. The parameter must then be passed down to the base DbContext
by calling :base(param)
.
So when (for example) InvestContext is initialised with DbContextOptions<InvestContext>
, it calls base(DbContextOptions<InvestContext>)
and EF throws an error because the call to the ConfigurationContext
constructor is receiving a parameter of type DbContextOptions<InvestContext>
instead of the required type DbContextOptions<ConfigurationContext>
.
I can work around this by building a new DbContextOptions<ConfigurationContext>
from the DbContextOptions<InvestContext>
object and passing that to base, but it seems like a hack and results in DbContext being initialised with DbContextOptions<ConfigurationContext>
for any context which inherits from ConfigurationContext.
So I guess I’m asking:
- Is that hack I’ve described a problem, or can I use it (ie. will there be unexpected effect of DbContext receiving
DbContextOptions<ConfigurationContext>
whenInvestContext
is constructed? - Is this limitation on inheritance intended, or just a side effect of the design choice requiring
DbContextOptions<DerivedContext>
- Is there perhaps a better way to do this which would allow for a clean inheritance model?
Thanks, and thanks for all the good work - Peter
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 2
- Comments: 28 (12 by maintainers)
Commits related to this issue
- Test for pattern suggested by @greggbjensen in #7533 Use both a public constructor for the typed options and a protected constructor for the un-typed options on a DbContext type that is intended to b... — committed to dotnet/efcore by ajcvickers 7 years ago
- Test for pattern suggested by @greggbjensen in #7533 Use both a public constructor for the typed options and a protected constructor for the un-typed options on a DbContext type that is intended to b... — committed to dotnet/efcore by ajcvickers 7 years ago
- Added support for creating derived ElsaContexts: - Added new protected constructor based on following post - https://github.com/dotnet/efcore/issues/7533 — committed to terry-delph/elsa-core by terry-delph 4 years ago
- Feature/mysql support efcore (#226) * Added MySqlContext * Added MySqlContextFactory * Added Pomelo.EntityFrameworkCore.MySql nuget package * Added initial MySqlContext migrations * Added suppo... — committed to elsa-workflows/elsa-core by terry-delph 4 years ago
I was able to resolve this without a hack by providing a protected constructor that uses
DbContextOptions
without any type. Making the second constructor protected ensures that it will not get used by DI.@theCuriousOne Created https://github.com/aspnet/EntityFramework.Docs/issues/594 to document this.
@ajcvickers What is the specific reason that
DbContextOptions<T>
is required for the derived class but the base only receivesDbContextOptions
?@Ettery I have been trying to reproduce this but have not been able to. The code already allows the TContext generic type to be of a derived DbContext type–see test code below. Can you post the exact exception message and stack trace you are seeing?