在ASP.NET Core中,EF Core上下文由内置的DI容器创建。在官方文档中,使用通用DbContextOptions<TContext>
:创建上下文
public class MyContext : IdentityDbContext<User> {
public MyContext(DbContextOptions<MyContext> options, ILogger<MyContext) logger) : base(options) { }
}
然而,也有非通用的例子:
public class MyContext : IdentityDbContext<User> {
public MyContext(DbContextOptions options, ILogger<MyContext) logger) : base(options) { }
}
根据源代码,它们之间的区别是:
类型参数:TContext:这些选项应用于的上下文的类型。
我想使用非泛型类型,因为在我的设计中,我有一个抽象的上下文,这在DI容器中不太好用。
那么,如果我使用非泛型类型,这到底意味着什么?我的上下文配置不正确
我想使用非泛型类型,因为在我的设计中,我有一个抽象的上下文,这与DI容器不太匹配。
这对DI容器来说很好。它只查看最派生的类型,即它试图实例化的类型。介于两者之间有一个基类这一事实并不相关。
注意,虽然你不能使用DbContextOptions<AbstractDbContext>
,但你不需要。你可以让基类使用DbContextOptions
,也可以让基类通用并使用DbContextOptions<ConcreteDbContext>
:
abstract class AbstractDbContext : DbContext
{
protected AbstractDbContext(DbContextOptions options) : base(options)
{
}
}
class ConcreteDbContext : AbstractDbContext
{
public ConcreteDbContext(DbContextOptions<ConcreteDbContext> options) : base(options)
{
}
}
或
abstract class AbstractDbContext<TContext> : DbContext
where TContext : AbstractDbContext<TContext>
{
protected AbstractDbContext(DbContextOptions<TContext> options) : base(options)
{
}
}
class ConcreteDbContext : AbstractDbContext<ConcreteDbContext>
{
public ConcreteDbContext(DbContextOptions<ConcreteDbContext> options) : base(options)
{
}
}
那么,如果我使用非泛型类型,这到底意味着什么?我的上下文配置不正确?
采用非泛型DbContextOptions
的构造函数通常也能工作。通常情况下,你是对的,服务提供商无法解决这个问题。但是,当您调用serviceCollection.AddDbContext<ConcreteDbContext>(...)
时,EF Core特别通知服务容器,当请求DbContextOptions
实例时,应该提供DbContextOptions<ConcreteDbContext>
实例。
请注意,只有当您有一个单独的上下文类型时,这才有效。如果你有多个,服务提供商没有足够的信息来确定你需要哪个。
这是基本IdentityDbContext
类(泛型和非泛型)构造函数的签名:
public IdentityDbContext(DbContextOptions options)
对我来说,这意味着它可以毫无问题地与非通用DbContextOptions
一起工作。
事实上,DbContextOptions
类的泛型版本和非泛型版本之间的唯一区别是泛型版本实现了abstract
非泛型版本。
尽管如此,将DbContextOptions<YourDbContext>
传递给YourDbContext
构造函数更安全,因为它可以确保调用者传递抽象类的正确实现(基本上是ContextType
属性)。