如何在 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&lt;OperationalStoreOptions&gt; 的设计时 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&lt;&gt;,您的整个 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的主要内容,如果未能解决你的问题,请参考以下文章

[EF]数据上下文该如何实例化?

使用带有DbSet的接口,可以使用EF Core吗?

ef core值对象不能引用到同一个

ef core值对象不能引用到同一个

如何使用 FreeSql 无缝接替 EF Core ?

如何在 EntityFramework Core 中使用部分类和部分 OnModelCreating 方法扩展 DbContext