簡體   English   中英

EF6:在DbSet.Local中包含導航屬性

[英]EF6: Include Navigation Properties in DbSet.Local

我正在從外部源加載數據作為xml,它被反序列化然后我循環對象以將它們匯集到我的域實體中。

為了創建數據之間的關系並減少數據庫調用,我編寫了一個擴展方法,嘗試從DbSet.Local中檢索項目,如果它沒有找到項目,那么它使用DbSet.SingleOrDefault()來查詢數據庫,如下所示。

public static TEntity SingleOrDefaultLocalFirst<TEntity>(this IDbSet<TEntity> set,
        Func<TEntity, bool> predicate) where TEntity : class
    {
        if (set == null)
            throw new ArgumentNullException("set");
        if (predicate == null)
            throw new ArgumentNullException("predicate");

        TEntity results = null;

        try
        {
            results = set.Local.SingleOrDefault(predicate);
        }
        catch (Exception e)
        {
            Debug.WriteLine(e.Message, "Error");
        }

        if (results != null)
        {
            return results;
        }
        return set.SingleOrDefault(predicate);
    }

try catch塊可以解決我想要解決的問題。

由於某種原因,未填充查詢本地存儲時的導航屬性。 所以,如果我使用類似的東西

(x=>x.Participant.Event.ExternalId==newItem.Id)

作為我的lambda,Participant nav屬性為null。

我覺得應該有一些方法讓這段代碼不能始終如一地生成空引用錯誤。

我已經嘗試在循環開始使用之前從數據庫中顯式加載Participant和Event數據

context.Participant.Load()

但這沒什么區別。

有人能告訴我為什么導航屬性為null以及如何以最有效的方式填充它們?

而且,如果有人想知道我為什么不使用Find(),那是因為外部數據被鍵入了許多屬性以及外部id字段,而不是我系統中的主鍵。

更新:

我不打算花時間來包含我的真實代碼,因為有太多的東西要削減到一個可用的例子,所以我將嘗試使用Customer / Order / OrderItem典型示例。

真正的問題是,當你有一個嵌套的實體,並嘗試使用類似的東西檢查存在:

var orderLine = context.OrderLineItems.Local.SingleOrDefault(x=>x.Order.Number == 1234)

即使Orders和Customers在使用之前明確加載到上下文中,它也會為Order拋出一個null引用錯誤

context.Orders.Load()

但是,如果你這樣做:

var orderLine = context.OrderLineItems.SingleOrDefault(x=>x.Order.Number == 1234)

它會工作。

我想了解為什么它在調用Local時不起作用。 為什么我們必須訪問數據庫以獲取已經加載到上下文中的相關導航屬性? 還是我錯過了什么?

好吧,我不確定為什么DbSet.Local.xx的行為與DbSet.xx不同,但我最終用作解決方案只是在我的lambda中檢查null:

SingleOrDefaultLocalFirst(x=>
...
x.Participant!=null &&
x.Participant.Event.ExternalId==newItem.Id &&
...);

這似乎阻止了我的擴展方法在首先檢查Local項時拋出錯誤,因此優雅地移動到調用數據存儲。

這里的問題是你“反序列化”的對象不是Proxied。

當您從DbSet<T>獲取項目時,實體框架不會為您提供類型為T對象。 相反,它會創建一個新類TProxy ,它overrides關聯屬性。 這樣,當你get屬性時,Entity Framework就會知道,並且可以攔截調用。

通過在Entity Framework之外反序列化對象,它沒有機會將“鈎子”添加到getter,它需要延遲加載。 因此,當您調用get對象的屬性時,EF不會延遲加載。

解決方案是使用Entity Framework實例化所有T對象,然后反序列化為這些對象,然后附加它們。

DbSet<T> set = ...;
T item = set.Create();
T deserialized = Deserialize(..);
AutoMapper.Map(deserialized, item);
set.Attach(item);

暫無
暫無

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

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