使用 EF7 和 VNext 访问 DBContext

Access DBContext using EF7 and VNext

在我的 MVC 6 项目中,我有 ApplicationDBContext class

public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
    protected override void OnModelCreating(ModelBuilder builder)
    {

    }
}

这已添加到我的服务中 Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
  //Other configurations removed for brevity
}

现在当我创建一个新的 Controller 时,它会询问我是否要使用 Entity Framework,我可以选择我的数据上下文。创建该控制器时,使用我假设的依赖注入将上下文传递到构造函数中。

public class CompanyController : Controller
{
    private ApplicationDbContext _context;

    public CompanyController(ApplicationDbContext context)
    {
        _context = context;
    }
}

现在,我不想在控制器中进行所有数据库交互,而是在我的其他 classes 中进行。我想不通的是如何从我的其他 classes 获取 ApplicationDbContext。从控制器传递它显然是行不通的,因为 classes 可以从控制器以外的其他地方调用。

如果我只是尝试 new ApplicationDbContext();,我会收到以下错误:

No database providers are configured. Configure a database provider by overriding OnConfiguring in your DbContext class or in the AddDbContext method when setting up services.

我觉得这应该很简单,但我完全迷失在这里。

ASP.NET核心基于依赖注入,因为你的上下文已经添加到你的依赖容器中,当你的控制器被实例化时,它会被框架自动注入。

根据评论编辑:

您可以设置 classes 以支持 DI,假设您有两个 class。一个取决于你的上下文,然后第二个取决于你的上下文和你的第一个 class :

public class MyClass
{
    private ApplicationDbContext _context;

    public MyClass(ApplicationDbContext context)
    {
        _context = context;
    }
}

public class AnotherClass
{
    private ApplicationDbContext _context;
    private MyClass _myClass;

    public AnotherClass(ApplicationDbContext context, MyClass myClass)
    {
        _context = context;
        _myClass = myClass;
    }
}

在启动时将您的 classes 作为临时依赖项添加到服务集合中,并让服务提供商为您解决它们的依赖项:

public void ConfigureServices(IServiceCollection services)
{
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));

    services.AddTransient<MyClass>();        
    services.AddTransient<AnotherClass>();

    //Other configurations removed for brevity
}

更改您的控制器以接受 MyClass 作为注入的依赖项:

public class CompanyController : Controller
{
    private ApplicationDbContext _context;
    private MyClass _myClass;

    public CompanyController(ApplicationDbContext context, MyClass myClass)
    {
        _context = context;
        _myClass = myClass;
    }
}

你也可以有另一个控制器,将 AnotherClass 作为注入依赖:

public class AnotherController : Controller
{
    private AnotherClass _anotherClass;

    public AnotherController(AnotherClass anotherClass)
    {
        _anotherClass = anotherClass;
        // _anotherClass will have both ApplicationDbContext and MyClass injected by the service provider
    }
}

您应该阅读 K. Scott Allen 的 docs of dependency injection of ASP.NET Core, it could help to understand basics of DI. Another article,其中解释了处理 DI 时的一些不良做法。

您可以创建一个服务 class 以与控制器相同的方式接收 DbContext。

public class SomeService
{
    private ApplicationDbContext MyDbContext { get; set; }

    public SomeService(ApplicationDbContext dbContext)
    {
       MyDbContext = dbContext;
    }
    public void MethodName()
    {
        // You can now do MyDbContext.SomeDomainModel
    }
}

然后在您的 ConfigureServices 方法中注册 Startup.cs 中的服务。

public void ConfigureServices(IServiceCollection services) {
  // <snipped>
  services.AddTransient<SomeService>();
}

现在,在 CompanyController 中,您可以在 SomeService 的构造函数中添加另一个参数,就像 ApplicationDbContext.

一样
public class CompanyController : Controller
{
    private ApplicationDbContext _context;
    private SomeService _someService;

    public CompanyController(ApplicationDbContext context, SomeService someService)
    {
        _context = context;
        _someService = someService;
    }
}

综上所述,我认为在控制器操作中执行逻辑以构建 ViewModel、访问 DbContext 没有任何问题。 DbContext 将您的业务逻辑(在控制器中)与 DAL 分开。有些人可能不同意我的看法,但您不需要添加额外的服务来进一步分离它们。您的操作方法中的大部分代码对于该操作都是唯一的,不会被其他操作重用。 IMO,那些 是要投入服务的代码片段。诸如发送电子邮件之类的事情。