在ASP.NET Core中,EF Core上下文由内置DI容器创建。在official documentation中,使用通用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容器配合使用。
所以,如果我使用非泛型类型,这究竟意味着什么?我的上下文未能正确配置?
答案 0 :(得分:3)
以下是基础IdentityDbContext
类的签名(通用和非通用)constructor:
public IdentityDbContext(DbContextOptions options)
对我来说意味着它可以毫无问题地使用非通用DbContextOptions
。
实际上,DbContextOptions
类的generic和non generic版本之间的唯一区别是通用版本实现了abstract
非泛型版本。
但是,将DbContextOptions<YourDbContext>
传递给YourDbContext
构造函数更安全,因为它可以确保调用者传递抽象类的正确实现(基本上是ContextType
属性)。
答案 1 :(得分:3)
我想使用非泛型类型,因为在我的设计中我有一个抽象的上下文,并且不能很好地与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>
实例。
请注意,这仅适用于您具有单个上下文类型的情况。如果您有多个,服务提供商没有足够的信息来确定您需要的信息。