实体框架导航属性不加载,直到新的DbContext建立
本文关键字:DbContext 建立 导航 框架 属性 加载 实体 | 更新日期: 2023-09-27 18:17:40
我对EF还比较陌生,所以如果我错过了一个明显的概念,请原谅我。
让我看看能不能化简一下…旧问题在编辑历史中,但我想我可以把它提炼出来:
FWIW, DbContext
是PER 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类,但我只是不能真正看到这样一个简单的调用的好处。
您的新订单实体实例没有被代理包装,因此延迟加载将无法工作。
你可以强制上下文加载导航属性。
db.Entry(order).Reference(o => o.YouProperty).Load();
或者你可以使用context的工厂创建一个实例来克服这个问题。
db.Orders.Create();
的实例将不会创建代理实例使用新操作符的实体。这可能不是问题,但如果你需要创建一个代理实例(例如,以便延迟加载或代理更改跟踪将工作),然后您可以使用Createhttps://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不同的名称。