将DbContext添加到所有类,而不仅仅是.NET Core中的控制器

时间:2017-09-13 22:01:40

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

我想将我当前的 DbContext 添加到我使用的任何类中,目前我只是将 _context 传递给公共变量。

在此控制器示例中,每次我想要创建项目时,我都会传递 _context

[HttpPost("receta/{id}")]
[APIauth("medico")]
public IActionResult PostItemsReceta(int id, [FromBody]Data[] items) {
    var tran = _context.Database.BeginTransaction(); //DBB transaction begins
    try {
        foreach (Data item in items)
            new Item(id, item, _context); //I pass the _context like this.

        tran.Commit();
        return Ok();

    } catch (Exception e) {
        tran.Rollback();
        return BadRequest("Not inserted!!");
    }            
}

在班级项目中我有这个

public class Item
{
    [Key]
    public int id { get; set; }
    public DateTime? fcaducidad { get; set; }
    public string nombre { get; set; }
    public Int32 diagnostico { get; set; }

    public Item() { }

    public Item (int receta, Data i, MyDbContext _context) {
        try {
            var q = $"EXEC ItemReceta_Insert @idItemFarmacia={i.itemFarmacia.id}" +
            $", @idDiagnostico={i.diagnostico}, @cantidad={i.cantidad}" +
            $", @receta={receta}, @posologia='{i.posologia}'";

            _context.Database.ExecuteSqlCommand(q); 
        } catch (Exception e) {
            throw new Exception("Error al insertar ItemReceta", e);
        }            
    }

    public static Item[] Report( int receta, MyDbContext _context) 
    {
        string q = $"EXEC Item_Report @receta={receta}";
        return _context.Item.FromSql(q).ToArray();
    }
}

我不想直接访问控制器中的上下文,因为我多次使用它,我想要

new Item(id, item);

new Item(id, item, _context);
Item.Report(bla, _context);
new WhatEverClass(name, age, _context);

2 个答案:

答案 0 :(得分:6)

我认为你并没有真正区分你的顾虑,有很多方法可以做到这一点,但是我会提出一种非常简单的方法来将事情注入你自己的课程中(I&#39 ; ll会遗漏解决方案中的一些属性以保持简单)。您需要做的主要事情是将您的课程注册为服务。所以..

首先,让你的物品成为POCO

 public class Item
    {
        public int Id { get; set; }
    }

现在将您的代码与您尝试将项目放入和放出数据库的方式相关联,使构造函数获取您的DbContext以便它将被注入

public class ItemService 
{
    private readonly ApplicationContext _context;

    public ItemService(ApplicationContext context)
    {
        _context = context;
    }

    public void Add(Item item)
    {
        // A paramatized query of some sort to prevent sql injection
        // see https://docs.microsoft.com/en-us/aspnet/core/data/ef-mvc/advanced
        var parameters = new List<object>();
        _context.Database.ExecuteSqlCommand("", parameters);
    }
}

现在,在您配置服务的地方添加您的项目服务

public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<ApplicationContext>();
            services.AddScoped<ItemService>();         
        }

现在在你的控制器构造函数中说你想要服务,

private readonly ItemService _itemService
public MyFancyPantsController(ItemService itemService)
{
  _itemService = itemService;
}

现在您可以在帖子上访问该服务

 [Route("post")]
    [HttpPost()]        
    public IActionResult PostItem()
    {
        // construct / deserialize items, then add them...
        _itemService.Add(new Item());
        return Ok();
    }

现在......你可能会发现你有很多实体(比如Item)并且为它们创建服务都是PITA,所以你可能想要更通用的Repository服务。

答案 1 :(得分:0)

只需在构造函数中使用using (var db = new DbContext()) { ... }

这将完全奏效:

public class AppDbContext : DbContext
{ 
  public DbSet<Item> Items { get; set; }
}

public class Data
{
  public int Id { get; set; }
  public string Value { get; set; }
}

public class Item
{
  public Item()
  {
  }

  public Item(IEnumerable<Data> data)
  {
    Data = data.ToList();
    using (var db = new AppDbContext())
    {
      db.Items.Add(this);
      db.SaveChanges();
    }
  }

  public override string ToString()
  {
    return Data != null ? $"Item:{Id}, Data:{string.Join(',', Data.Select(i => i.Value))}" : $"Item:{Id}, Data:None";
  }

  public int Id { get; set; }
  public ICollection<Data> Data { get; set; }
}

...

var i1 = new Item(new[] {new Data {Value = "1"}, new Data {Value = "2"}});
var i2 = new Item(new[] {new Data {Value = "3"}, new Data {Value = "4"}});

using (var db = new AppDbContext())
{
  db.Items.Include(i => i.Data).ToList().ForEach(Console.WriteLine);
}

有很多理由说明这是一个坏主意(无法创建持久化项目,无论如何都需要默认构造函数,不能轻松执行批量插入,高耦合,无法测试),但它似乎是我的解决方案这正是你的解决方案,所以我不确定这是否有帮助?

值得注意的是,由于连接池,使用以下内容创建 new DbContext会更好,更高效。

using (var db = new AppDbContext())
{
    ...
}

比手动或使用DI传递一个单例对象;这是因为上下文在内部缓存查询结果,如果您将其用作单例,则基本上存在缓慢的内存泄漏。

即。这个:public Item (int receta, Data i, MyDbContext _context)实际上比几个using (var db = new AppDbContext() { ... }明显更糟,除非您专门使用结果缓存。