簡體   English   中英

實體框架代碼優先 - 根據子TPH類的類型進行選擇

[英]Entity Framework Code First - select based on type of child TPH class

我目前正在使用Entity Framework 4處理一個使用Table Per Hierarchy表示使用單個表的一組類的項目。 這種方式的工作方式是該表表示狀態,不同的狀態與不同的其他類相關聯。

所以你可能會想象它看起來像這樣,忽略了所有州共享的公共字段:

InactiveState 
  has a -> StateStore

ActiveState 
  has a -> ActivityLocation

CompletedState
  has a -> CompletionDate

每個州都有一個屬於它的所有InventoryItem的集合。

現在,我的庫存中的每個項目都有許多狀態,其中歷史記錄中的最后一個是當前狀態。 要保存在列表中,我有一個快捷方式字段,指向我的庫存的當前狀態:

public class InventoryItem : Entity
{

    // whole bunch of other properties

    public virtual ICollection<InventoryState> StateHistory { get; set; }

    public virtual InventoryState LastState { get; set; }

}

我遇到的第一個問題是,我想找到所有處於Active狀態的InventoryItems。

事實證明, Linq-To-Entities不支持GetType(),所以我不能使用像InventoryRepository.Get().Where( x => x.LastState.GetType() == someType )這樣的語句InventoryRepository.Get().Where( x => x.LastState.GetType() == someType ) 可以使用is運算符,但這需要一個固定類型,而不是像這樣的方法:

 public ICollection<InventoryItem> GetInventoryItemsByState( Type state )
 {
     return inventoryRepository.Get().Where( x => x.LastState is state );
 }

在進行Linq查詢之前,我必須根據類型運行某種if語句,這感覺不對。 InventoryItem列表可能會變大,所以我需要在EF級別執行此操作,我無法將整個列表拉入內存並使用GetType()。

在這種情況下我有兩個問題,關聯得足夠緊密,我認為它們可以合並,因為它們可能反映了我對自己缺乏了解:

  • 是否可以使用Linq To Entities查找共享子表類型的項目列表?
  • 鑒於我沒有使用延遲加載,是否可以使用TPH Include子表類型的相關項目,例如,如果我有一個InactiveState作為我的InventoryItem的子項,我可以為該InactiveState預加載StateStore?

是否可以使用Linq To Entities查找共享子表類型的項目列表?

我認為除了使用if / switch檢查類型並使用is TOfType<T>構建過濾器表達式之外,我認為不可能。 您可以將此邏輯封裝到擴展方法中,例如,以便維護一個位置和可重用的方法:

public static class Extensions
{
    public static IQueryable<InventoryItem> WhereIsLastState(
        this IQueryable<InventoryItem> query, Type state)
    {
        if (state == typeof(InactiveState))
            return query.Where(i => i.LastState is InactiveState);
        if (state == typeof(ActiveState))
            return query.Where(i => i.LastState is ActiveState);
        if (state == typeof(CompletedState))
            return query.Where(i => i.LastState is CompletedState);

        throw new InvalidOperationException("Unsupported type...");
    }
}

要像這樣使用:

public ICollection<InventoryItem> GetInventoryItemsByState(Type state)
{
   return inventoryRepository.Get().WhereIsLastState(state).ToList();
}

我不知道是否可以使用.NET Expression API手動構建i => i.LastState is XXX表達式,並基於傳遞給方法的Type (老實說,我也會感興趣,但我幾乎沒有關於表達操作的線​​索來回答這個問題。)

鑒於我沒有使用延遲加載,是否可以使用TPH包含子表類型的相關項目,例如,如果我有一個InactiveState作為我的InventoryItem的子項,我可以為該InactiveState預加載StateStore?

我不確定我是否理解正確,但通常急於加載Include不支持對特定包含的孩子進行任何過濾或附加操作。

避免這種限制並仍然在單個數據庫往返中獲得結果的一種方法是使用如下所示的投影:

var result = context.InventoryItems
    .Select(i => new
    {
        InventoryItem = i,
        LastState = i.LastState,
        StateStore = (i.LastState is InactiveState)
            ? (i.LastState as InactiveState).StateStore
            : null
    })
    .AsEnumerable()
    .Select(x => x.InventoryItem)
    .ToList();

如果查詢是跟蹤查詢(在上面的示例中)並且關系不是多對多(它們不在您的示例中),則上下文將在實體加載到上下文時修復關系,是InventoryItem.LastStateInventoryItem.LastState.StateStore (如果LastState的類型為InactiveState )將被設置為已加載的實體( 就好像它們已經加載了急切加載)。

暫無
暫無

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

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