如何在 EF Core 中实例化 DbContext
Posted
技术标签:
【中文标题】如何在 EF Core 中实例化 DbContext【英文标题】:How to instantiate a DbContext in EF Core 【发布时间】:2018-11-20 03:29:55 【问题描述】:我也设置了 .net 核心项目和数据库上下文。但是由于这个错误,我还不能开始使用 dbContext-
"没有给出与所需形式相对应的参数 参数'选项'"
控制器:
public IActionResult Index()
using (var db = new BlexzWebDb())
return View();
数据库上下文代码:
public class BlexzWebDb : DbContext
public BlexzWebDb(DbContextOptions<BlexzWebDb> options)
: base(options)
public DbSet<User> Users get; set;
public DbSet<Role> Roles get; set;
public DbSet<AssignedRole> AssignedRoles get; set;
附上错误图片。该问题的可能解决方法是什么? 提前致谢
【问题讨论】:
@Stefan 代码已添加 @johnCogdle 您的数据上下文 (BlexzWebDb) 的邮政编码 您需要阅读 ASP.NET Core 中的依赖注入:docs.microsoft.com/en-us/aspnet/core/fundamentals/…。你试图做的事情根本上是错误的。 @SOusedtobegood 这绝不是根本错误的。您不知道 OP 正在为此开展的项目的要求、时间或金钱限制、质量属性或任何其他要求。这是在正确的情况下做事的一种非常有效的方式。确实,使用 DI 可以实现很多事情,但即使是 Microsoft 也不会从中产生问题:Instance pooling can increase throughput in high-scale scenarios such as web servers by re-using DbContext instances, rather than creating new instances for each request.
请注意,其中没有“你做对了”。
完全同意@Zimano - 从根本上来说并没有错。当您只需要一个连接时,这只是一种简单的连接方式。如果您需要动态建立连接,例如当您想在使用 asp.net web api 时摆脱多租户数据库架构时怎么办?我可以想象的前进方式是不依赖依赖注入,而是根据请求创建一个 dbcontext 对象并将其动态指向用户的个人数据库。我看不到通过 DI(EF 5.0 之前)实现此目的的方法
【参考方案1】:
从 ConnectionString 实例化 DbContext 的新对象
var connectionstring = "Connection string";
var optionsBuilder = new DbContextOptionsBuilder<ApplicationDbContext>();
optionsBuilder.UseSqlServer(connectionstring);
ApplicationDbContext dbContext = new ApplicationDbContext(optionsBuilder.Options);
// Or you can also instantiate inside using
using(ApplicationDbContext dbContext = new ApplicationDbContext(optionsBuilder.Options))
//...do stuff
【讨论】:
这如何回答这个问题? 我们可以像这样实例化 DbContext @DerekPollard OP 询问如何实例化 EF 上下文,这个答案显示了如何。由于 OP 特别不明白他们必须向该构造函数提供参数,因此回答者也展示了如何传入选项。 这应该是正确的答案。如果你不想要 DI,你不应该受到同行的压力。 我同意@neeohw!这一定是正确的答案。比如我需要一个单独的用于迁移的连接字符串(在后台任务中),不同的权限,我这里不需要实现依赖(而且很难做到)【参考方案2】:注意
在撰写本文时,EF Core 与依赖注入框架的使用并不像现在这样广为人知。这个答案从 DI 的角度给出了这个问题的答案,这在当时帮助了 OP。
另一个答案为您提供了一种使用 new
运算符实例化 DbContext 的常规方法。
TL;DR,3 个选项:
选项 1
在应用配置过程中注册 DbContext:
public void ConfigureServices(IServiceCollection services)
services.AddDbContextPool<BlexzWebDb>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
并使用 DI 框架来检索它:
public class SomeController : Controller
private readonly BlexzWebDb _db;
//the framework handles this
public SomeController(BlexzWebDb db)
_db = db;
选项 2
如果您正在寻找使用 IOptions<OperationalStoreOptions>
的设计时 IdentityDbContext
,请参阅:Add migration for ApiAuthorizationDbContext from another project - EF Core
选项 3
或使用new
运算符并提供详细信息,有关详细信息,请参阅@Qamar Zaman 的答案。
长答案,以及为什么 DI 是一种享受
在 EF Core 中,将一些 DbContextOptions 传递给构造函数是很常见的。
所以一般来说,构造函数是这样的:
public BlexzWebDb(DbContextOptions<BlexzWebDb> options) : base(options)
如您所见,没有无参数构造函数形式的有效重载:
因此,这不起作用:
using (var db = new BlexzWebDb())
显然,您可以在构造函数中传入Option
对象,但还有另一种选择。所以,
改为
.Net Core 已在其根源中实现了 IoC。好的,这意味着;您不创建上下文,而是要求框架根据您之前定义的一些规则为您提供上下文。
示例:您将在某处注册您的 dbcontext,(Startup.cs):
//typical configuration part of .net core
public void ConfigureServices(IServiceCollection services)
//some mvc
services.AddMvc();
//hey, options!
services.AddDbContextPool<BlexzWebDb>(options =>
options.UseSqlServer(Configuration.GetConnectionString("BlexzWebConnection")));
//...etc
现在注册部分已经完成,您可以从框架中检索您的上下文。例如:通过控制器中的构造函数反转控制:
public class SomeController : Controller
private readonly BlexzWebDb _db;
//the framework handles this
public SomeController(BlexzWebDb db)
_db = db;
//etc.
为什么?
那么,为什么不直接提供参数和new
呢?
new
的使用没有任何问题 - 在很多场景中它的效果最好。
但是,Inversion Of Control 被认为是一种很好的做法。在执行asp dotnet core
时,您可能会经常使用它,因为大多数库都提供了使用它的扩展方法。如果您不熟悉它,并且您的研究允许它;你一定要试一试。
因此,我不会提供“只是一种实例化对象的方法”,而是尝试让您走上这条轨道 - 与框架内联。之后会省去一些麻烦。此外,否则“使用激活器的 CreateInstance” 将与答案一样有效;-)
一些链接:
MSDN Fundamentals MSDN Dependency Injection Wikipedia Inversion Of Control【讨论】:
你真棒!多谢,伙计。非常漂亮和干净的描述 请注意,如果您使用.AddDbContext<>
,您的整个 ioc 树现在都会暴露给 ef(例如,对于日志记录,从 Ef 2.1 开始,您甚至可以将服务注入模型)。这对您来说可能很重要,也可能无关紧要,但我们明确选择退出这种模式,例如:)
@zaitsman:这让我想知道;那你用什么模式?
那你就可以用@hasan的回答了,虽然貌似缺少实际的无参数构造函数,你可以手动添加。
@Eutherpy:顺便说一句,确保是框架提供的配置选项之一。我不知道确切的方法调用,但每个 IoC 框架都有它们。因此,即使在这种情况下,我也建议您使用该框架;-)【参考方案3】:
作为@Stefan 的回答的补充,还有另一种方法可以实现这一点。您可以在 DbContext 类的 OnConfiguring 方法中设置 db 连接字符串,而无需在 startup.cs 中添加 DbContext 服务。
Setting.cs
public static class Setting
public static string ConnectionString get; set;
Startup.cs
Setting.ConnectionString = Configuration.GetSection("ConnectionStrings:BlexzDbConnection").Value;
BlexzWebDb.cs
public class BlexzWebDb : DbContext
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
if (!optionsBuilder.IsConfigured)
optionsBuilder.UseSqlServer(Setting.ConnectionString);
HomeController.cs
public class HomeController : Controller
private readonly BlexzWebDb db;
public HomeController()
this.db = new BlexzWebDb();
//etc.
【讨论】:
很酷的方式。不知道那个! ? 那么Setting
类呢? ? 你如何实例化配置,获取连接并保存到这个类? ?
这是正确的答案。将 EntityFrameworkCore 和 EntityFrameworkCore .SqlServer 添加到 Web 应用程序会破坏 DDD 原则【参考方案4】:
EF Core 3.1 的代码示例:
public class Test
private readonly IServiceProvider _serviceProvider;
public Test(IServiceProvider serviceProvider)
_serviceProvider = serviceProvider;
public async Task<RequestResult> Handle(...)
await using var context = CreateContext();
...
private DocumentContext CreateContext()
var options = _serviceProvider.GetService<IOptions<DocumentContextOptions>>();
return new DocumentContext(options);
【讨论】:
你好,DocumentContextOptions
是什么?
@trnj,这是自定义类型,其中包含 connectionString 可能还有其他内容以上是关于如何在 EF Core 中实例化 DbContext的主要内容,如果未能解决你的问题,请参考以下文章
如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext