我对EF来说还是比较新的,所以请原谅我,如果我错过了一个明显的概念.
让我看看我是否可以简化这个…老问题在编辑历史中,但我想我可以将其提炼出来:
FWIW,DbContext是PER REQUEST,而不是静态,这就是第一个例子有效的原因.此时不在控制器上使用DI / IoC.
public class OrdersController : ApiController {
private MyDbContext db = new MyDbContext();
//controller methods....
protected override void Dispose(bool disposing) {
db.Dispose();
}
}
作品(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;
}
作品(单一请求)(但我知道这是一种可怕的做法):
//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;
}
因此,在我看来,在上下文中添加一个新的前所未见的实体会产生一些副作用,然后尝试将其导航属性设置为填充.但是如果你创建一个新的DbContext …即使在同一个请求中,它也必须直接命中该实体的数据库,而不是使用内存副本,这样导航属性就会神奇地起作用.那是让我难过的部分.
工作方案
//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来说,经历所有这些问题的需要似乎比我的其他(通常是简短的)经验更加费力.我想也许我应该使用ViewModel并将VM属性映射到代理实例,而不是直接尝试使用EF类,但我真的看不到像这样简单调用的好处.
最佳答案 您的新订单实体实例未被代理包装,因此延迟加载将不起作用.
您可以强制上下文加载导航属性.
db.Entry(order).Reference(o => o.YouProperty).Load();
或者您可以使用上下文的工厂来创建实例来克服此问题.
db.Orders.Create();
A proxy instance will not be created if you create an instance of an
entity using the new operator. This may not be a problem, but if you
need to create a proxy instance (for example, so that lazy loading or
proxy change tracking will work) then you can do so using the Create
method of DbSet.