EF - Navigation属性为null,即使在重新加载实体后也是如此,但在重新启动程序时仍然有效

Lah*_*hey 5 c# entity-framework nullreferenceexception ef-model-first

编辑

我做了一些测试并发现,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
Run Code Online (Sandbox Code Playgroud)

谁可以给我解释一下这个?

编辑结束

在我的程序中,用户有一个订单列表,他可以向其添加新订单.用户还可以向订单添加订单商品,但由于OrderItem - > Item navigation属性为null,即使在保存并重新加载订单后,这也无法正常运行.

OrderItem
---------
OrderId
ItemId
Quantity
DateCreated
---------
Item <- navigation property
Order
Run Code Online (Sandbox Code Playgroud)

当用户更改订单并按下保存按钮时,程序从视图中获取数据,更新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
                });
            }
Run Code Online (Sandbox Code Playgroud)

然后,在orderModel类中......

    public void AddOrUpdate(Order order)
    {
        if (order.Id == 0)
        {
            context.Orders.Add(order);
        }

        context.SaveChanges();
    }
Run Code Online (Sandbox Code Playgroud)

然后更新订单表,触发一个事件,该事件触发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();
Run Code Online (Sandbox Code Playgroud)

当调用PopulateOrderItemTableControl()方法时,我开始遇到麻烦..

        foreach (OrderItem oi in activeOrder.OrderItem)
        {
            orderItems.Add(new ItemViewObject(oi));
        }
Run Code Online (Sandbox Code Playgroud)

因为在创建新的ItemViewObject时,我需要通过它的navigation属性获取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();
Run Code Online (Sandbox Code Playgroud)

然后我必须重新启动程序,但在这样做之后,订单项加载完全正常.因此,只有在向订单添加新订单商品,保存订单,然后重新下订单并尝试显示订单商品时才会发生这种情况.

此外,这仅适用于之前未添加到订单中的新项目.因此,如果我创建一个新项目并将其添加到订单,单击保存按钮,我将得到一个空异常,需要重新启动.重新启动后,该项目加载正常.如果我然后删除订单项,保存订单,重新添加项目并再次保存,它不会崩溃.

希望这对某人有意义.

干杯!

注意:我先使用模型.

Sla*_*uma 19

该行为实际上是预期的,并有解释:

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
Run Code Online (Sandbox Code Playgroud)

这里的关键问题是你OrderItem用new运算符创建new :

ord.OrderItem.Add(new OrderItem() {
    ItemId = 8, Quantity = 2, DateCreated = DateTime.Now });
Run Code Online (Sandbox Code Playgroud)

这意味着它不是一个能够通过延迟加载加载导航属性的动态代理.要手动创建代理,您应该使用:

var newOrderItem = context.OrderItems.Create();
newOrderItem.ItemId = 8;
newOrderItem.Quantity = 2;
newOrderItem.DateCreated = DateTime.Now;

ord.OrderItem.Add(newOrderItem);
Run Code Online (Sandbox Code Playgroud)

之后context.SaveChanges()你应该能够Item通过延迟加载(基于外键值ItemId)加载属性.context.Orders.FirstOrDefault()不需要"重新加载"订单,也不需要使用新的上下文.

  • 完美的答案,非常感谢! (4认同)