簡體   English   中英

實體框架有時未加載子對象/集合的內容

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

我開始遇到一個問題,即使用延遲加載無法正確加載Entity Framework中的子集合。

最突出的例子是我的Orders對象-每個訂單都有一個或多個與其關聯的訂單行(即,已訂購哪些產品以及訂購多少產品的列表)。 有時,當程序運行時,您可以打開一些訂單,所有訂單行(對於每個訂單)都為空白。 重新啟動該程序,它們可能會重新出現。 這是斷斷續續的。

我已經通過日志和調試確認子集合中沒有條目:

    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;
    }

對於相同的訂單,有時會說“正在加載0條訂單行...”,有時會說“正在加載4條訂單行...”。

加載訂單列表時,我無法使用“急切加載”,因為當可能只有幾個打開時,我不想加載所有訂單的所有訂單行-我需要保持加載速度與可能,並且僅在需要時加載它們,因此延遲加載。

它不僅發生在Orders對象上,有時還發生在其他子集合上,但效果完全相同。

有人知道EF為什么要這樣做以及我可以如何解決嗎? 這是一個很大的問題-我的程序中不能有空的訂單行!

可能會或可能不會使用的額外信息:

這是WPF MVVM應用程序。 與網站共享的數據層使用存儲庫/工作單元模式。

在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);
    }

然后,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);
        }

延遲加載用於在您訪問導航屬性時自動加載相關實體。 但是,在這種情況下,您不是自動執行,而是手動執行。

為此,您可以禁用延遲加載,並使用顯式加載,如下所示:

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

(此外,使用此技術,您可以應用過濾器)。

延遲加載的問題可能是DbContext壽命長的結果,該DbContext在給定的時間點緩存相關實體,然后在不影響數據庫的情況下稍后重用此緩存,因此它已經過時了。 即,一個DbContext為一條訂單找到3條訂單行並將其緩存。 其他(在db上下文之外)向此訂單添加了2條額外的新訂單行。 然后,您從第一個數據庫上下文訪問訂單行,並獲得過時的3條訂單行,而不是數據庫中的5條。 從理論上講,有幾種方法可以重新加載/刷新DbContext上的緩存數據,但是您可能會遇到麻煩。 您寧願使用我上面建議的顯式加載。 如果您看到有關Load方法文檔 ,則可以閱讀以下內容:

從數據庫加載實體集合。 請注意,上下文中已經存在的實體不會被數據庫中的值覆蓋。

但是,最安全的選擇始終是處置DbContext並創建一個新的DbContext (請閱讀上面代碼塊的第二句話)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM