如何在类库项目中正确定义DBContext

本文关键字:定义 DBContext 项目 类库 | 更新日期: 2023-09-27 18:25:51

我使用实体框架7,创建了两个项目。一个项目是ASP.NET 5 Web API项目,另一个是类库项目(包),我想将所有数据访问层逻辑存储在其中。这样,我就可以将此包用于以后的另一个报告项目和其他可能提供的附加服务。

基本上,我在webapi项目的控制器中有一个简单的帖子,它调用了我的数据库项目中的一个函数。当函数启动数据库时,它表示数据库未定义,即使在两个项目中都定义了数据库。


错误

{"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."}

代码

数据库项目:InsertPerson

public int InsertPerson(tbl_Person person)
{
    using (var db = new AppContext())
    {
        try
        {
            db.tbl_Person.Add(person);
            db.SaveChanges();
            return person.PersonID;
        }
        catch
        {
            return 0;
        }
    }
}

配置文件

Web API项目:启动。cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<AppContext>(options =>
            options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<AppContext>();
    services.AddMvc();
}

Web API项目:appsettings.json

{
  "Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=localhost;Database=testDB;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Verbose",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

Web API项目:Project.json

{
  "userSecretsId": "blah,
  "version": "1.0.0-rc1-final",
  "compilationOptions": {
    "emitEntryPoint": true
  },
  "dependencies": {
    "DataLibrary": "",
    "Microsoft.AspNet.Authentication.OAuthBearer": "1.0.0-beta7",
    "Microsoft.AspNet.Http.Abstractions": "1.0.0-rc1-final",
    "Microsoft.AspNet.Identity.EntityFramework": "3.0.0-rc1-final",
    "Microsoft.AspNet.IISPlatformHandler": "1.0.0-rc1-final",
    "Microsoft.AspNet.Mvc": "6.0.0-rc1-final",
    "Microsoft.AspNet.Server.Kestrel": "1.0.0-rc1-final",
    "Microsoft.AspNet.StaticFiles": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.FileProviderExtensions": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0-rc1-final",
    "Microsoft.Extensions.Configuration.UserSecrets": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc1-final",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc1-final",
    "Remotion.Linq": "2.0.1"
  },
  "commands": {
    "web": "Microsoft.AspNet.Server.Kestrel"
  },
  "frameworks": {
    "dnx451": { },
    "dnxcore50": { }
  },
  "exclude": [
    "wwwroot",
    "node_modules"
  ],
  "publishExclude": [
    "**.user",
    "**.vspscc"
  ]
}

数据库项目:Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<AppContext>(options =>
            options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<AppContext>();
    services.AddMvc();
}

数据库项目:appsettings.json

{
  "Data": {
    "DefaultConnection": {
      "ConnectionString": "Server=localhost;Database=testDB;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
  },
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Verbose",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

数据库项目:AppContext.cs

namespace DataLibrary
{
    public class AppContext : IdentityDbContext<ApplicationUser>
    {
        public DbSet<tbl_Person> tbl_Person { get; set; }
        public static AppContext Create()
        {
            return new AppContext();
        }
        protected override void OnModelCreating(ModelBuilder builder)
        {
            new tbl_PersonMap(builder.Entity<tbl_Person>());
            base.OnModelCreating(builder);
        }
    }
}

如何在类库项目中正确定义DBContext

示例代码中的问题似乎是您正在新建AppContext实例,而不是从ServiceProvider解决它。当您以这种方式初始化DbContext时,将为该上下文隐式创建一个新的ServiceProvider,并且Startup.cs中的任何配置都不受该上下文的尊重。如果您在OnConfiguring中配置上下文,而对应用程序的其余部分中的依赖项注入不感兴趣,那么您希望使用这种模式。

在这种情况下,我希望您通过构造函数注入来获得AppContext。对于这种解决方案,您还需要在ServiceCollection中注册数据访问层类。结果应该看起来更像这样:

数据库项目:AppContext.cs

namespace DataLibrary
{
    public class AppContext : IdentityDbContext<ApplicationUser>
    {
        public DbSet<tbl_Person> tbl_Person { get; set; }
        protected override void OnModelCreating(ModelBuilder builder)
        {
            new tbl_PersonMap(builder.Entity<tbl_Person>());
            base.OnModelCreating(builder);
        }
    }
}

数据库项目:PersonHelper.cs

namespace DataLibrary
{
    class PersonHelper
    {
        private readonly AppContext db;
        public PersonHelper(AppContext context)
        {
            db = context;
        }
        public int InsertPerson(tbl_Person person)
        {
            try
            {
                db.tbl_Person.Add(person);
                db.SaveChanges();
                return person.PersonID;
            }
            catch
            {
                return 0;
            }
        }
    }
}

Web API项目:启动。cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddEntityFramework()
        .AddSqlServer()
        .AddDbContext<AppContext>(options =>
            options.UseSqlServer(Configuration["Data:DefaultConnection:ConnectionString"]));
    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<AppContext>();
    services.AddScoped<PersonHelper>();
    services.AddMvc();
}

Web API项目:MyController.cs

[Route("api/[controller]")]
public class MyController : Controller
{
    private readonly personHelper helper;
    public MyController(PersonHelper helper)
    {
        this.helper = helper;
    }
    // POST api/my
    [HttpPost]
    public void Post([FromBody]string value)
    {
        var person = new tbl_Person
        {
          // ...
        }
        return helper.InsertPerson(person);
    }
}

您甚至可以考虑为数据访问层类在IServiceCollection上添加一个扩展方法,以帮助减少配置中的重复,尤其是在添加更多通用服务时。

我找到了一种方法,但我仍然不相信这是最好的方法。在包含插入函数的类文件中,我添加了这个函数,这样当从web api项目调用它时,web api中的appcontext就会传递给数据库项目。话虽如此,我不确定是否有更优雅的方法

public class fnCommon
{
    private readonly AppContext db;
    public fnCommon(AppContext context)
    {
        this.db = context;
    }
    public int InsertPerson(tbl_Person person)
    {
        try
        {
            db.tbl_Person.Add(person);
            db.SaveChanges();
            return person.PersonID;
        }
        catch
        {
            return 0;
        }
    }
}