简体   繁体   English

实体框架有时未加载子对象/集合的内容

[英]Entity Framework is sometimes not loading the contents of Child Objects/Collections

I've started to have a problem where child collections in Entity Framework are not being loaded properly with Lazy Loading. 我开始遇到一个问题,即使用延迟加载无法正确加载Entity Framework中的子集合。

The most prominent example of this is my Orders object - each Order has one or more Order Lines associated with it (ie. a list of which products have been ordered and how many). 最突出的例子是我的Orders对象-每个订单都有一个或多个与其关联的订单行(即,已订购哪些产品以及订购多少产品的列表)。 Sometimes, when the program is run, you can open up some orders and all the order lines (for every order) will be blank. 有时,当程序运行时,您可以打开一些订单,所有订单行(对于每个订单)都为空白。 Restart the program, and they might re-appear. 重新启动该程序,它们可能会重新出现。 it's pretty intermittent. 这是断断续续的。

I have confirmed that there are no entries in the child collection through logging & debugging: 我已经通过日志和调试确认子集合中没有条目:

    private ObservableCollection<OrderLine> LoadOrderLines()
    {
        Log.Debug("Loading {0} order lines...", this.Model.OrderLines.Count);

        var result = new ObservableCollection<OrderLine>();

        foreach (var orderLine in this.Model.OrderLines)
        {
            result.Add(orderLine);
        }

        return result;
    }

Sometimes it will say "Loading 0 order lines..." and sometimes "Loading 4 order lines..." for the same order. 对于相同的订单,有时会说“正在加载0条订单行...”,有时会说“正在加载4条订单行...”。

I can't use Eager Loading when I load the list of orders because I don't want to load all the order lines for all the orders when only a few of them might ever be opened - I need to keep the loading as fast as possible and only load things as they are needed, hence lazy loading. 加载订单列表时,我无法使用“急切加载”,因为当可能只有几个打开时,我不想加载所有订单的所有订单行-我需要保持加载速度与可能,并且仅在需要时加载它们,因此延迟加载。

It's not only the Orders object that it is happening on, it sometimes happens on other child collections too, but the effect is exactly the same. 它不仅发生在Orders对象上,有时还发生在其他子集合上,但效果完全相同。

Anybody have any idea why EF is doing this and what I can do to fix it? 有人知道EF为什么要这样做以及我可以如何解决吗? It's a huge problem - I can't have empty order lines in my program when they should be there! 这是一个很大的问题-我的程序中不能有空的订单行!

Extra info that may or my not be of use: 可能会或可能不会使用的额外信息:

This is a WPF MVVM application. 这是WPF MVVM应用程序。 The data layer, which is shared with the website, uses a Repository/Unit of Work pattern. 与网站共享的数据层使用存储库/工作单元模式。

In the OrdersRepository: 在OrdersRepository中:

    public IEnumerable<Order> GetOrders(DateTime fromDate, DateTime toDate, IEnumerable<string> sources, bool? paidStatus, bool? shippedStatus, bool? cancelledStatus, bool? pendingStatus)
    {
        if (sources == null)
        {
            sources = this.context.OrderSources.Select(s => s.SourceId);
        }

        return
            this.context.Orders.Where(
                o =>
                o.OrderDate >= fromDate
                && o.OrderDate < toDate
                && sources.Contains(o.SourceId)
                && (!paidStatus.HasValue || ((o.ReceiptId != null) == paidStatus.Value))
                && (!shippedStatus.HasValue || ((o.ShippedDate != null) == shippedStatus.Value))
                && (!pendingStatus.HasValue || (o.IsPending == pendingStatus.Value))
                && (!cancelledStatus.HasValue || (o.Cancelled == cancelledStatus.Value))).OrderByDescending(
                    o => o.OrderDate);
    }

The OrdersViewModel then loads the orders, creates an orderViewModel for each one and puts them in an ObservableCollection: 然后,OrdersViewModel加载订单,为每个订单创建一个orderViewModel并将它们放入ObservableCollection中:

var ordersList = this.unitOfWork.OrdersRepository.GetOrders(this.filter).ToList();

        foreach (var order in ordersList)
        {
            var viewModel = this.viewModelProvider.GetViewModel<OrderViewModel, Order>(order);

            this.orders.Add(viewModel);
        }

Lazy loading is for loading the related entities automatically when you acces the navigation property. 延迟加载用于在您访问导航属性时自动加载相关实体。 But, in this case, you're not doing it automatically, but manually. 但是,在这种情况下,您不是自动执行,而是手动执行。

To do so, you can disable lazy loading, and use explicit loading, like this: 为此,您可以禁用延迟加载,并使用显式加载,如下所示:

context.Entry(order).Collection(o => o.orderLines).Load();

(Besides, using this technique, you can apply filters). (此外,使用此技术,您可以应用过滤器)。

Your problem with lazy loading can be a consequence of a long lived DbContext that caches the related entities at a given point in time, and reuses this cache later, without hitting the DB, so it's outdated. 延迟加载的问题可能是DbContext寿命长的结果,该DbContext在给定的时间点缓存相关实体,然后在不影响数据库的情况下稍后重用此缓存,因此它已经过时了。 Ie one DbContext finds 3 order lines for an order and caches them. 即,一个DbContext为一条订单找到3条订单行并将其缓存。 Something else, (outside the db context), adds 2 extra new order lines to this order. 其他(在db上下文之外)向此订单添加了2条额外的新订单行。 Then you access the order lines from the first db context and get the outdated 3 order lines, instead of the 5 that there are in the DB. 然后,您从第一个数据库上下文访问订单行,并获得过时的3条订单行,而不是数据库中的5条。 There are several ways in wich you could, thoretically, reload/refresh the cached data on the DbContext, but you can get into trouble. 从理论上讲,有几种方法可以重新加载/刷新DbContext上的缓存数据,但是您可能会遇到麻烦。 You'd rather use the explicit loading as I suggested above. 您宁愿使用我上面建议的显式加载。 If you see the docs for Load method , you can read this: 如果您看到有关Load方法文档 ,则可以阅读以下内容:

Loads the collection of entities from the database. 从数据库加载实体集合。 Note that entities that already exist in the context are not overwritten with values from the database. 请注意,上下文中已经存在的实体不会被数据库中的值覆盖。

However, the safest option is always to dispose the DbContext and create a new one. 但是,最安全的选择始终是处置DbContext并创建一个新的DbContext (Read the second sentence of the block above). (请阅读上面代码块的第二句话)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM