在 Asp.Net 核心中注入 DbContext。具体类型还是接口?
Inject DbContext in Asp.Net Core. Concrete type or interface?
在我正在注入的 Asp.Net 核心项目上 Entity Framework DbContext:
public MessageRepository(MyDbContext context) {
}
配置为:
services
.AddEntityFramework()
.AddSqlServer()
.AddDbContext<Context>(x => x.UseSqlServer(connectionString);
我应该创建一个接口 IMyDbContext,然后注入它吗?
public class MyDbContext : DbContext, IMyDbContext { }
public MessageRepository(IMyDbContext context) {
}
在所有 ASP.NET 核心示例中,我看到具体类型 MyDbContext 正在被注入,而不是接口 ...
我应该选择什么选项?
我们总是注入一个接口,因为它更容易在单元和集成测试中模拟。
- 您愿意更改
MessageRepository
构造函数的签名吗?它依赖于具体类型。
- 您是否为您的代码编写测试?使用和接口可以更容易地模拟数据库上下文。
如果您对以上一项或多项回答“否”,请注入具体类型;否则,注入接口。
[编辑]
使用以下内容。
context services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
在我看来,你应该像@Uli 所说的那样始终依赖一个接口,但是当涉及到 DbContext 时,你需要记住你正在公开 EntityFramework Core 的 DbContext 的所有方法
public class MyDbContext : DbContext, IMyDbContext { }
在那种情况下,您不需要实现任何公开的方法,因为 DbContext 会为您处理。
但是,如果 EF 代码更改了 DbContext 并且您对项目进行了更新,那么您将处于每次更新 IMyDbContext 以及所有单元测试的痛苦境地。在我看来,这会让你很头疼。
这个answers/questions可以帮助你理解为什么
Unit testing EF - how to extract EF code out from BL?
目前我自己在做一个项目,我决定使用 2 个这样的界面
public interface IDbContext : IDisposable
{
DbContext Instance { get; }
}
和
public interface IApplicationDbContext : IDbContext
{
DbSet<MyEntity> MyEntities { get; set; }
...
}
然后我的具体 DbContext 将只实现应用程序上下文接口
public class ApplicationDbContext : DbContext, IApplicationDbContext
{
public DbContext Instance => this
public DbSet<MyEntity> MyEntities { get; set; }
}
这允许我将应用程序上下文的实现作为应用程序上下文接口注入,同时还允许我通过实例访问 DbContext 方法 属性 getter 而无需添加所需的方法从 DbContext class 到接口。
到现在为止,效果很好。
在我正在注入的 Asp.Net 核心项目上 Entity Framework DbContext:
public MessageRepository(MyDbContext context) {
}
配置为:
services
.AddEntityFramework()
.AddSqlServer()
.AddDbContext<Context>(x => x.UseSqlServer(connectionString);
我应该创建一个接口 IMyDbContext,然后注入它吗?
public class MyDbContext : DbContext, IMyDbContext { }
public MessageRepository(IMyDbContext context) {
}
在所有 ASP.NET 核心示例中,我看到具体类型 MyDbContext 正在被注入,而不是接口 ...
我应该选择什么选项?
我们总是注入一个接口,因为它更容易在单元和集成测试中模拟。
- 您愿意更改
MessageRepository
构造函数的签名吗?它依赖于具体类型。 - 您是否为您的代码编写测试?使用和接口可以更容易地模拟数据库上下文。
如果您对以上一项或多项回答“否”,请注入具体类型;否则,注入接口。
[编辑] 使用以下内容。
context services.AddScoped<IApplicationDbContext>(provider => provider.GetService<ApplicationDbContext>());
在我看来,你应该像@Uli 所说的那样始终依赖一个接口,但是当涉及到 DbContext 时,你需要记住你正在公开 EntityFramework Core 的 DbContext 的所有方法
public class MyDbContext : DbContext, IMyDbContext { }
在那种情况下,您不需要实现任何公开的方法,因为 DbContext 会为您处理。
但是,如果 EF 代码更改了 DbContext 并且您对项目进行了更新,那么您将处于每次更新 IMyDbContext 以及所有单元测试的痛苦境地。在我看来,这会让你很头疼。
这个answers/questions可以帮助你理解为什么
Unit testing EF - how to extract EF code out from BL?
目前我自己在做一个项目,我决定使用 2 个这样的界面
public interface IDbContext : IDisposable
{
DbContext Instance { get; }
}
和
public interface IApplicationDbContext : IDbContext
{
DbSet<MyEntity> MyEntities { get; set; }
...
}
然后我的具体 DbContext 将只实现应用程序上下文接口
public class ApplicationDbContext : DbContext, IApplicationDbContext
{
public DbContext Instance => this
public DbSet<MyEntity> MyEntities { get; set; }
}
这允许我将应用程序上下文的实现作为应用程序上下文接口注入,同时还允许我通过实例访问 DbContext 方法 属性 getter 而无需添加所需的方法从 DbContext class 到接口。
到现在为止,效果很好。