1

J'ai le modèle suivant (simplifié):Comment inclure une propriété héritée dans un héritage "inégal" avec Entity Framework?

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

Comme l'a dit "graphique":

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

Maintenant, je veux charger tous CartItems et comprennent des données de la classe Hôtel si le type de CartItem est un HotelCartItem.

Voici comment j'essaie de le faire, mais il échoue avec un "ne déclare pas une propriété de navigation avec le nom" Hôtel "."

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

Si je laisse la .Include("Hotel") la propriété Hôtel de CartItems de type Hôtel est nul.

Ma question:
Y at-il un moyen de contourner ce problème?

Répondre

0

Je fini par diviser la requête en plusieurs parties:

  1. charge le poste parent, un « panier ».
  2. Pour chacun des différents types que j'ai eu (HotelCartItem et TransferCartItem) J'interrogé le db pour un ensemble de seulement ce type:
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; 
    } 
} 

Appelez avec:

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

3. Ajoutez les CartItems à la collection de l'objet Cart.

0

Le chargement fastidieux des propriétés de navigation sur les sous-classes est délicat. Je n'ai pas trouvé d'autre moyen que de les charger séparément. La façon facile de le faire est l'enregistrement gestionnaire ObjectMaterialized personnalisée (uniquement dans EF 4.0) sur ObjectContext:

context.ObjectMaterialized += RegisterEagerLoadingStrategies; 

Et la méthode de gestionnaire ressemble:

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

Cette solution a un problème N + 1. N + 1 signifie que si votre requête principale renvoie N HotelCartItems, vous exécuterez N + 1 requêtes dans la base de données (chaque requête LoadProperty appelle une requête supplémentaire). Cette méthode est également appelée pour chaque entité chargée (pas seulement pour HotelCartItem). Donc, cette solution est vraiment mauvaise pour le chargement d'un grand nombre d'entités.

Une autre méthode de chargement des propriétés de navigation à partir d'entités associées consiste à diviser votre requête en deux requêtes. La première requête chargera CartItems et la deuxième requête chargera les hôtels pour les articles de chariot chargés dans la première requête (mêmes conditions). Les références aux hôtels dans les articles de panier doivent être automatiquement définies si vos entités sont toujours attachées au contexte.