1

次のモデルがあります(簡略化):

abstract class CartItem { EntityReference<Cart> Cart; }
class HotelCartItem : CartItem { EntityReference<Hotel> Hotel; }
class TransferCartItem : CartItem { }
class Hotel { }

「グラフィカルに」表現されているように:

CartItem
|<- HotelCartItem
|   |-> Hotel
|
|<- TransferCartItem

CartItem のタイプが HotelCartItem の場合は、すべての CartItem をロードし、Hotel クラスのデータを含めます。

これが私がやろうとしている方法ですが、「「ホテル」という名前のナビゲーションプロパティを宣言していません」で失敗します。

var q = from cartitems in context.CartItems
            .Include("Hotel")
        where cartitems.CART_ID == CartID
        select cartitems;

タイプ Hotel のCartItems.Include("Hotel")の Hotel プロパティを省略すると、null になります。

私の質問:
これを回避する方法はありますか?

4

2 に答える 2

0

サブクラスでのナビゲーション プロパティのイーガー ロードは注意が必要です。それらを別々にロードする以外に他の方法は見つかりませんでした。これを行う簡単な方法は、ObjectContext にカスタム ObjectMaterialized ハンドラー (EF 4.0 のみ) を登録することです。

context.ObjectMaterialized += RegisterEagerLoadingStrategies;

ハンドラ メソッドは次のようになります。

private static void RegisterEagerLoadingStrategies(object sender, ObjectMaterializedEventArgs e)
{
  var context = (ObjectContext)sender;

  var cartItem = e.Entity as HotelCartItem;
  if (cartItem != null)
  {
    context.LoadProperty(cartItem, o => o.Hotel); 
  }
}

このソリューションには N + 1 問題があります。N + 1 は、メイン クエリが N 個の HotelCartItems を返す場合、データベースで N + 1 個のクエリを実行することを意味します (各 LoadProperty は追加のクエリを呼び出します)。また、このメソッドは、読み込まれたすべてのエンティティに対して呼び出されます (HotelCartItem だけでなく)。したがって、このソリューションは、多数のエンティティをロードするのには非常に適していません。

関連エンティティからナビゲーション プロパティを読み込むもう 1 つの方法は、クエリを 2 つのクエリに分割することです。最初のクエリは CartItems をロードし、2 番目のクエリは最初のクエリでロードされたカート項目の Hotels をロードします (同じ条件)。エンティティがまだコンテキストに関連付けられている場合、カート項目内のホテルへの参照は自動的に設定されます。

于 2010-11-25T13:06:04.813 に答える
0

最終的に、クエリをいくつかの部分に分割しました。

  1. 親アイテム「カート」をロードします。
  2. 取得したさまざまなタイプ (HotelCartItem および TransferCartItem) ごとに、そのタイプのみのセットをデータベースに照会しました。
private IQueryable<T> GetCartItemQuery<T>(Guid CartID) where T : CartItem
{
    if (typeof(T) == typeof(HotelCartItem))
    {
        var q = from ci in db.CartItems.OfType<T>()
                    .Include("Hotel")
                where ci.CART_ID == CartID
                select ci;
        return q;
    }
    else
    {
        var q = from ci in db.CartItems.OfType<T>()
                where ci.CART_ID == CartID
                select ci;
        return q;
    }
}

次のように呼び出します。

var hotels = GetCartItemQuery<HotelCartItem>(CartID);
var transfers = GetCartItemQuery<TransferCartItem>(CartID);

3. CartItems を Cart オブジェクトのコレクションに追加します。

于 2011-02-15T13:45:01.937 に答える