繁体   English   中英

实体框架核心依赖项注入模型

[英]Entity Framework Core dependency injection to models

我是ASP.NET Core / C#的新手,正在尝试学习。 我已经阅读了教程,观看了视频,甚至买了一本书。 我想将AppDBcontext注入模型。

这是我的Startup

    public void ConfigureServices(IServiceCollection services)
    {
        // Add framework services.
        string dbConnection = Configuration["ConnectionStrings:AzureSQL"];

        services.AddDbContext<AppDbContext>(options => {
            options.UseSqlServer(dbConnection);
        });

        services.AddScoped<AppDbContext>();
        services.AddMvc();
    }

和我的AppDbContext.cs

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options)
    : base(options) { }

    public DbSet<Monthly> Monthly { get; set; }
    public DbSet<Bill> Bill { get; set; }
}

我从模型中尝试过类似的东西

public class Bill
{
    public AppDbContext _ctx;
    public Bill(AppDbContext db)
    {
        _ctx = db;
    }

    public class BillGetParams
    {
        public string MonthlyID { get; set; }
        public string UserID { get; set; }
        public string BillID { get; set; }
    }

    public int ID { get; set; }
    public int? MonthlyID { get; set; }
    public string BillName { get; set; }
    public string Comment { get; set; }
    public int? Amount { get; set; }
    public bool? Payed { get; set; }
    public bool? Recursive { get; set; }
    public string UserID { get; set; }
    public string UUID { get; set; }
    public DateTime? CreatedAt { get; set; }

    public static async Task<List<Bill>> LoadBills(BillGetParams billParams)
    {
        var bills = _ctx.Bill.FromSql($@"
        SELECT * FROM bills WHERE MonthlyId={billParams.MonthlyID}");

        return await bills.ToListAsync();
    }

    public static async Task<Bill> LoadBill(BillGetParams param)
    {
        var bill = _ctx.Bill.FromSql($@"
            SELECT * FROM bills
                WHERE UserID='{param.UserID}' AND ID='{param.BillID}'
        ");

        return await bill.SingleOrDefaultAsync();
    }

编辑:为Bill类和使用_ctx方法添加了部分代码,还通过删除static和private-> public来更新构造函数;

我收到一个错误:

System.NullReferenceException:对象引用未设置为对象的实例。

因为似乎db分配给_ctx从未发生过。

我不确定哪个是最好的,但是我像这样之前使用AppDbContext 我应该继续这样使用吗?

using(var ctx = new AppDbContext())
{
    var bills = ctx.Bill.FromSql($@"select 1 from bills")
    // do stuff
}

从Internet的示例中,DI在控制器上运行良好。.但是我不想在控制器上执行SQL工作。.是否有更好的方法在dotnet抽象SQL /数据访问? 还是我做错了?

solution1:所以在阅读完之后,尝试了一下,尝试了@Bharat的解决方案,并进行了实验。 我用最简单的方法解决了问题。希望我是对的。 我在使用Bill.LoadBill() BillController中添加了此BillController ,现在可以很好地访问SQL了。

    private Bill _bill;
    public BillController(AppDbContext db)
    {
        _bill = new Bill(db);
    }

谢谢!

System.NullReferenceException

之所以得到System.NullReferenceException: Object reference not set to an instance of an object. 是因为您的构造方法是private

 private Bill(AppDbContext db) { _ctx = db; } 

解决方案:您的构造函数应为public

否则,无法在自己的类之外访问它。 您可以通过在_ctx = db上放置一个断点来测试它,您将看到它没有被调用。

为了进一步阅读和理解,我建议您阅读此Microsoft文档: ASP.NET Core中的依赖项注入

我看到的最大错误是这个:

public class Bill
{
    public AppDbContext _ctx;
    public Bill(AppDbContext db)
    {
        _ctx = db;
    }

    public static async Task<List<Bill>> LoadBills(BillGetParams billParams)
    {
         var bill = _ctx... //trying to acces an instance property in static context, does not work. and shouldn't even compile.
    }
}

恳求建筑变革

我认为为模型提供直接访问其实例的方法很好,但是即使这样做是为了填充额外的属性或列表,也请不要这样做。

这样,您可以在整个应用程序中拆分我们的DataAccess代码(sql)。 相反,最好将所有dataAcces分组在控制器中,或者甚至在单独的项目中作为服务分组。

服务的优势在于:

  • 您可以通过IOC容器解决它
  • 没有奇怪的模型构造函数的问题(现在每个模型都需要AppDbContext,即使它不需要它)
  • 如果服务实现了相同的接口,则可以轻松地将其替换为另一个服务。 (并且您使用此课程界面)
  • 静态方法不可覆盖,而虚拟实例方法则不可覆盖。 (当您的项目变大时,这将导致问题)

这将导致以下代码:

public class EntityFrameworkBillService : IBillService
{
    public AppDbContext _ctx;
    public Bill(AppDbContext db)
    {
        _ctx = db;
    }

    public async Task<List<Bill>> GetBills(BillGetParams billParams)
    {
         var bill = _ctx... //trying to acces an instance property in static context, does not work. and shouldn't even compile.
    }
}
//startup.cs:
services.AddTransient<IBillService,EntityFrameworkBillService>()

//Usage 
public MyController(IBillService billService) //constructor
{
    var dollahBills = billService.GetBills();
}

 //And if you really wish this method to be there, and be lazy (but be warned: its an anti pattern)
public class Bill
{
    public static async Task<List<Bill>> GetBills(BillGetParams billParams)
    {
         //Make sure your ServiceProvider is available as static on Program in startup.cs.
         return Program.ServiceProvider.Resolve<IBillService>().GetBills(billParams);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM