4

私は現在、階層ごとのテーブルを使用して単一のテーブルを使用してクラスの 1 つのセットを表すプロジェクトで Entity Framework 4 を使用しています。これが機能する方法は、このテーブルが状態を表し、さまざまな状態がさまざまな他のクラスに関連付けられていることです。

したがって、すべての州が共有する共通のフィールドを無視すると、次のように見えると想像できます。

InactiveState 
  has a -> StateStore

ActiveState 
  has a -> ActivityLocation

CompletedState
  has a -> CompletionDate

各状態には、それに属するすべての InventoryItems のコレクションがあります。

現在、インベントリ内の各アイテムには多くの状態があり、履歴の最後のものが現在の状態です。リストに保存するために、インベントリの現在の状態を指すショートカット フィールドがあります。

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 )。演算子を使用できisますが、次のようなメソッドを持つことができるのではなく、固定型が必要です。

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

Linq クエリを作成する前に、型に基づいて何らかの if ステートメントを実行する必要がありますが、これは間違っていると感じています。InventoryItem リストは大きくなる可能性が高いため、これを EF レベルで行う必要があります。たとえば、リスト全体をメモリに取り込んで GetType() を使用することはできません。

この状況で 2 つの質問がありますが、これらはおそらく私の側の理解不足を反映しているため、組み合わせることができるほど密接に関連していると思います。

  • Linq To Entities を使用して、子テーブル タイプを共有するアイテムのリストを見つけることは可能ですか?
  • 遅延読み込みを使用していないInclude場合、TPH を使用して子テーブル タイプのアイテムを関連付けることは可能ですか?
4

1 に答える 1

3

Linq To Entities を使用して、子テーブル タイプを共有するアイテムのリストを見つけることは可能ですか?

is Tタイプをチェックし、 orを使用してフィルター式を構築する if/switch を使用する以外に、別の方法で可能だとは思いませんOfType<T>。たとえば、このロジックを拡張メソッドにカプセル化して、維持する場所を 1 つにし、再利用可能なメソッドにすることができます。

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 API を使用して、メソッドに渡された に基づいてi => i.LastState is XXX式を手動で作成できるかどうかはわかりません。(正直なところ、私も興味がありますが、自分で答えるための表現操作についてはほとんど手がかりがありません。)ExpressionType

遅延読み込みを使用していない場合、TPH を使用して子テーブル タイプの関連アイテムを含めることは可能ですか?

私が正しく理解しているかどうかはわかりませんが、一般的に熱心な読み込みでIncludeは、含まれている特定の子に対するフィルタリングや追加操作はサポートされていません。

この制限を回避し、1 回のデータベース ラウンドトリップで結果を取得する 1 つの方法は、次のようなプロジェクションを使用することです。

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();

クエリが追跡されたクエリ (上記の例にある) であり、関係が多対多ではない (例にはありません) 場合、エンティティがコンテキストに読み込まれると、コンテキストは関係を修正します。 isInventoryItem.LastStateおよびInventoryItem.LastState.StateStore( LastStateis が type の場合InactiveState) は、読み込まれたエンティティに設定されます (あたかも熱心な読み込みで読み込まれたかのように)。

于 2013-04-18T17:47:35.163 に答える