使用EF7和VNext访问DBContext

时间:2016-04-15 00:38:49

标签: c# entity-framework asp.net-core dbcontext entity-framework-core

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

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;
    }
}

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

如果我只是尝试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.

我觉得这应该是简单的事情,但我完全迷失在这里。

2 个答案:

答案 0 :(得分:3)

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

根据评论进行编辑:

您可以设置课程以支持DI,假设您有两个课程。一个取决于你的背景,然后取决于你的背景和你的第一堂课:

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;
    }
}

在启动时将您的类添加为服务集合中的瞬态依赖项,并让服务提供商为您解析它们的依赖项:

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
    }
}

您应该阅读ASP.NET核心依赖注入的docs,它可以帮助理解DI的基础知识。来自K. Scott Allen的另一个article解释了在处理DI时的一些不良做法。

答案 1 :(得分:2)

您可以创建一个以与控制器相同的方式接收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,那些是放入服务的代码片段。比如发送电子邮件等等。