编辑
我做了一些测试,发现 Item 导航属性仅在处理上下文/创建新上下文时才有效。
DataContext context = new DataContext();
Order ord = context.Orders.FirstOrDefault();
ord.OrderItem.Add(new OrderItem() { ItemId = 8, Quantity = 2, DateCreated = DateTime.Now });
// At this point, both Order and Item navigation property of the OrderItem are null
context.SaveChanges();
// After saving the changes, the Order navigation property of the OrderItem is no longer null, but points to the order. However, the Item navigation property is still null.
ord = context.Orders.FirstOrDefault();
// After retrieving the order from the context once again, Item is still null.
context.Dispose();
context = new DataContext();
ord = context.Orders.FirstOrDefault();
// After disposing of the context and creating a new one, then reloading the order, both Order and Item navigation props are not null anymore
有人能给我解释一下吗?
编辑结束
在我的程序中,用户有一个订单列表,他可以向其中添加新订单。用户还可以向订单中添加订单项,但由于 OrderItem -> Item 导航属性为 null,即使在保存并重新加载订单后,这在 atm 上也无法正常工作。
OrderItem
---------
OrderId
ItemId
Quantity
DateCreated
---------
Item <- navigation property
Order
当用户更改订单并按下保存按钮时,程序从 View 中获取数据,更新 activeOrder 并将其发送到 orderModel,将其添加为新订单或更新现有订单。
GetOrderDataFromView() ..
...
// Check for existing item, update if match found, add new item if not
foreach (ItemViewObject oi in orderItems)
{
var existingOrderItem = activeOrder.OrderItem.Where(o => o.ItemId == oi.ItemId).SingleOrDefault();
if (existingOrderItem != null)
{
existingOrderItem.Quantity = oi.Quantity;
}
else
{
activeOrder.OrderItem.Add(new OrderItem()
{
ItemId = oi.ItemId,
Quantity = oi.Quantity,
DateCreated = DateTime.Now
});
}
然后,在 orderModel 类中 ...
public void AddOrUpdate(Order order)
{
if (order.Id == 0)
{
context.Orders.Add(order);
}
context.SaveChanges();
}
然后更新订单表,触发一个事件,该事件触发 OrderSelectionChanged() 方法。此时,通过从 orderModel 中检索它来重新加载订单(返回 context.Orders.Where...)...
// Get values from selected order and populate controls
if (view.OrderTable.SelectedRows.Count != 0)
{
OrderViewObject ovm = (OrderViewObject)view.OrderTable.SelectedRows[0].DataBoundItem;
activeOrder = orderModel.GetById(ovm.OrderId);
PopulateOrderItemTableControl();
当调用 PopulateOrderItemTableControl() 方法时,我开始遇到麻烦..
foreach (OrderItem oi in activeOrder.OrderItem)
{
orderItems.Add(new ItemViewObject(oi));
}
因为在创建新的 ItemViewObject 时,我需要通过其导航属性获取 orderItem 的项目。但是,orderItem.Item 导航属性为 null,我在这里遇到异常 ...
public ItemViewObject(OrderItem orderItem)
{
dateCreated = orderItem.DateCreated;
// Retrieve latest item details, with effective date older or equal to the creation date of the order item
var details = orderItem.Item.ItemDetails.Where(i => i.DateEffective <= dateCreated)
.OrderByDescending(i => i.DateEffective)
.FirstOrDefault();
然后我必须重新启动程序,但在这样做之后,订单项加载得非常好。因此,这只会在向订单添加新订单项、保存订单、然后重新加载订单并尝试显示其订单项时发生。
此外,这只会发生在之前未添加到订单中的新商品上。因此,如果我创建一个新项目并将其添加到订单中,单击保存按钮,我将得到一个空异常并需要重新启动。重新启动后,项目加载正常。如果我随后删除订单项目、保存订单、重新添加项目并再次保存,它不会崩溃。
希望这对某人有意义。
干杯!
注意:我先用模型。
最佳答案
该行为实际上是预期的并且有解释:
DataContext context = new DataContext();
Order ord = context.Orders.FirstOrDefault();
ord.OrderItem.Add(new OrderItem() {
ItemId = 8, Quantity = 2, DateCreated = DateTime.Now });
// At this point, both Order and Item navigation property of the OrderItem
// are null
// Explanation: That's clear because you don't set Order and Item property
context.SaveChanges();
// After saving the changes, the Order navigation property of the OrderItem
// is no longer null, but points to the order. However, the Item navigation
// property is still null.
// Explanation: SaveChanges internally fixes relationships with objects that are
// attached to the context. Order is attached, Item is not. That's why only
// the Order property is set
ord = context.Orders.FirstOrDefault();
// After retrieving the order from the context once again, Item is still null.
// Explanation: Because the Order is already attached a new query won't replace
// it. The entity remains the same as before.
context.Dispose();
context = new DataContext();
ord = context.Orders.FirstOrDefault();
// After disposing of the context and creating a new one, then reloading the
// order, both Order and Item navigation props are not null anymore
// Explanation: In a new context the Order will be loaded as a proxy. So, now
// lazy loading will work and load the Item property
这里的关键问题是您使用 new
运算符创建新的 OrderItem
:
ord.OrderItem.Add(new OrderItem() {
ItemId = 8, Quantity = 2, DateCreated = DateTime.Now });
这意味着它不是能够通过延迟加载来加载导航属性的动态代理。为了手动创建代理,您应该使用:
var newOrderItem = context.OrderItems.Create();
newOrderItem.ItemId = 8;
newOrderItem.Quantity = 2;
newOrderItem.DateCreated = DateTime.Now;
ord.OrderItem.Add(newOrderItem);
在 context.SaveChanges()
之后,您现在应该能够通过延迟加载加载 Item
属性(基于外键值 ItemId
).不需要使用 context.Orders.FirstOrDefault()
来“重新加载”订单,也不需要使用新的上下文。
关于c# - EF - 导航属性为空,即使在重新加载实体之后,但在程序重新启动时有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22042146/