实体框架导航属性不加载,直到新的DbContext建立

本文关键字:DbContext 建立 导航 框架 属性 加载 实体 | 更新日期: 2023-09-27 18:17:40

我对EF还比较陌生,所以如果我错过了一个明显的概念,请原谅我。

让我看看能不能化简一下…旧问题在编辑历史中,但我想我可以把它提炼出来:

FWIW, DbContextPER REQUEST,而不是static,这就是第一个例子有效的原因。此时未在控制器上使用DI/IoC。

public class OrdersController : ApiController {
    private MyDbContext db = new MyDbContext();
    //controller methods....
    protected override void Dispose(bool disposing) {
      db.Dispose();
    }
}

Works(2个单独的请求):

//request 1: client code sends in a new order to be added to db
public Order Post([FromBody]Order order) {
  db.Orders.Add(order);
  db.SaveChanges();
  return order;
}
//request 2: someone punches a button to send an email to CS about this order
public void NotifyCustomerService(int orderid) {
  var order = db.Orders.Find(orderid);
  //do email code here
}

破碎(单个请求):

//request: client code sends in a new order to be added to db AND notifies CS at same time
public Order Post([FromBody]Order order) {
  db.Orders.Add(order);
  db.SaveChanges();
  //notify CS via email here (nav properties are not populating)
  return order;
}

Works(单个请求)(但我知道这是可怕的做法):

//request: client code sends in a new order to be added to db AND notifies CS at same time (using a new dbcontext in the notification code)
public Order Post([FromBody]Order order) {
  db.Orders.Add(order);
  db.SaveChanges();
  using(var db2 = new MyDbContext()) {
    var sameOrderWTF = db.Orders.Find(order.ID);
    //notify CS via email using sameOrderWTF instance here (nav properties ARE populating)
  }
  return order;
}

所以,在我看来,有一些副作用添加一个新的从未见过的实体到上下文,然后试图让它的nav属性填充。但是如果你创建一个新的DbContext…即使在相同的请求中,它也必须直接命中该实体的DB,而不是使用in-mem副本,然后nav属性神奇地工作。这才是难倒我的地方。

工作方案

//request: client code sends in a new order to be added to db AND notifies CS at same time
public Order Post([FromBody]Order o) {
  Order order = db.Orders.Create();
  db.Orders.Add(order);
  //copy values from input to proxy instance
  db.Entry(order).CurrentValues.SetValues(o);
  //copy input lines to proxy instance (same process as order for each line)
  o.OrderLines.ToList().ForEach(l => {
    var line = db.OrderLines.Create();
    db.OrderLines.Add(line);
    db.Entry(line).CurrentValues.SetValues(l);
    order.OrderLines.Add(line);
  });
  db.SaveChanges();
  //notify CS via email here (nav properties are not populating)
  return order;
}

因此,虽然我们认为这个问题已经得到了解答(感谢Uber Bot),但需要经历所有这些似乎比我使用ASP的其他经验(公认的短暂)更费力。NET MVC和EF。我想也许我应该使用ViewModels和映射虚拟机属性到代理实例,而不是试图直接使用EF类,但我只是不能真正看到这样一个简单的调用的好处。

实体框架导航属性不加载,直到新的DbContext建立

您的新订单实体实例没有被代理包装,因此延迟加载将无法工作。

你可以强制上下文加载导航属性。

db.Entry(order).Reference(o => o.YouProperty).Load();

或者你可以使用context的工厂创建一个实例来克服这个问题。

db.Orders.Create();
的实例将不会创建代理实例使用新操作符的实体。这可能不是问题,但如果你需要创建一个代理实例(例如,以便延迟加载或代理更改跟踪将工作),然后您可以使用Create
https://msdn.microsoft.com/en-us/data/jj592886.aspx

仅供参考…可以简化为.....你应该添加验证。

//only handles new orders...as is
//Assumes!!! Order is of a type which is a db Entity! (Table)
//Assumes that you populated "order" with all the required properties.
public Order Post([FromBody]Order order) 
{
    db.Orders.Add(order);
    db.SaveChanges();
    return order;
}

检查代码....再次,在方法签名中似乎"Order"不是一个db Order实体,不确定如果不是,您应该重命名它,以便它不会混淆。例如,将其重命名为OrderDTO或其他与db Order不同的名称。