如何在類庫項目中正確定義DBContext?

asp.net-web-api c# entity-framework entity-framework-core

我正在使用實體框架7並創建了兩個項目。一個項目作為ASP.NET 5 Web API項目,另一個是類庫項目(包),我希望將所有數據訪問層邏輯存儲在其中。這樣我就可以將此包用於另一個報告項目,我可以提供的其他服務。

基本上我在web api項目的控制器中有一個簡單的帖子,它在我的數據庫項目中調用一個函數。當函數啟動數據庫時,它表示數據庫未定義,即使它在兩個項目中都已定義。


錯誤

{"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項目: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();
}

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

一般承認的答案

看起來您在示例代碼中的問題是您正在新建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);
        }
    }
}

數據庫項目:PersonH​​elper.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項目: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.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;
        }
    }
}



許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
這個KB合法嗎? 是的,了解原因