Как включить наследуемое свойство в «неравномерное» наследование с Entity Framework? - PullRequest
1 голос
/ 25 ноября 2010

У меня есть следующая модель (упрощенно):

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

Как выражено "графически":

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

Теперь я хочу загрузить все CartItems ивключите данные из класса Hotel, если тип CartItem - это HotelCartItem.

Вот как я пытаюсь это сделать, но это не удается с "не объявляет свойство навигации с именем" Hotel ". "

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

Если я опущу .Include("Hotel"), свойство отеля CartItems типа Hotel будет нулевым.

Мой вопрос:
Есть лиспособ обойти это?

Ответы [ 2 ]

0 голосов
/ 15 февраля 2011

Я разделил запрос на несколько частей:

  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.

0 голосов
/ 25 ноября 2010

Стремительная загрузка навигационных свойств на подклассы сложна. Я не нашел другого способа, кроме как загрузить их отдельно. Самый простой способ сделать это - зарегистрировать пользовательский обработчик ObjectMaterialized (только в EF 4.0) в ObjectContext:

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). Так что это решение действительно плохо для загрузки большого количества объектов.

Еще один подход к загрузке свойств навигации из связанных объектов - это разделение вашего запроса на два запроса. Первый запрос загрузит CartItems, а второй запрос загрузит Hotels для элементов корзины, загруженных в первом запросе (те же условия). Ссылки на отели в корзине должны автоматически устанавливаться, если ваши объекты все еще привязаны к контексту.

...