2010-11-03 7 views
2

Supposons que j'ai les classes Animal, Cat et Dog. Cat et Dog sont hérités de Animal. Envisagez le code suivant:Comment utiliser linq-to-nhibernate pour interroger des classes héritées?

var query = from animal in session.Linq<Animal>() 
      where 
      animal.Color == "White" 
      select animal; 

Comment puis-je ajouter un critère à la requête ci-dessus pour interroger sur le type d'entité? Par exemple quelque chose comme animal.Type == typeof(Cat).

+0

ne pourriez-vous pas simplement dire 'd'animal en session.Linq ()'? – Pedro

+0

Si pour une raison quelconque vous ne pouvez pas faire ce que Pedro suggère; jetez un oeil à ma réponse à cette question similaire: http://stackoverflow.com/questions/3451395/nhibernate-linq-nhibernate-queryexception-could-not-resolve-property-profile/3467077#3467077 – DanP

+0

@Pedro: Non, Je ne peux pas. Parce que le type d'animal n'est pas connu avant l'exécution. –

Répondre

1

Vous pouvez mapper une propriété en lecture seule qui utilise votre colonne discriminante dans le cadre d'une formule. L'interrogation de cette colonne vous permettra de distinguer les types avec le fournisseur nhcontrib actuel.

D'autres conseils peuvent être trouvés dans ma réponse à une question similaire here.

11

Ceci est soutenu dans le nouveau fournisseur:

var query = from animal in session.Query<Animal>() 
      where animal.Color == "White" && 
        animal is Cat 
      select animal; 
+0

Nice ... attendait que ce soit disponible! – DanP

+0

est-il disponible uniquement dans NHibernate 3? –

+0

Je le crois, mais ça ne fait pas de mal d'essayer. –

1

La version de LINQ to NHibernate qui est compatible avec NH 2.1.2 ne prend pas en charge l'interrogation par type à l'exécution.

// DOES NOT WORK WITH NH 2.1.2 & LINQ-to-NH 
var desiredType = typeof(Cat); 
var query = from animal in session.Linq<Animal>() 
      where animal.Color == "White" 
       && animal.GetType() == desiredType 
      select animal; 
// This results in an ArgumentOutOfRangeException in the LINQ provider 

Vous pouvez le faire en mémoire comme suggéré dans les commentaires:

var desiredType = typeof(Cat); 
var query = from animal in session.Linq<Animal>() 
      where animal.Color == "White" 
      select animal; 
var animals = query.ToList(); 
var whiteCats = from animal in animals.AsQueryable() 
       where animal.GetType() == desiredType 
       select animal; 

En effectuant query.ToList(), vous collationne tous les animaux blancs et en effectuant ensuite le type requête à l'aide LINQ-to-Objects. (Selon votre requête et mappage exacte, vous devrez peut-être vous inquiéter des proxies paresseux et donc vérifier si le type de l'objet est assignable au type désiré.) Cela présente l'inconvénient majeur de lire plus de données que nécessaire pour filtrer par animal tapez en mémoire. Selon votre domaine et la requête, cela peut ou non être un gros problème.

Si vous ne pouvez pas effectuer une mise à niveau vers NHibernate trunk (alias NH3), je recommande de ne pas utiliser LINQ-to-NHibernate pour cette requête et d'utiliser plutôt Criteria.

var desiredType = typeof(Cat); 
var query = session.CreateCriteria(desiredType) 
        .Add(Restrictions.Eq("Color", "White") 
        .List<Animal>(); 

N.B. Cela devrait être évident, mais permettez-moi de l'énoncer explicitement. Il n'y a aucune raison pour laquelle vous ne pouvez pas utiliser les critères pour cette requête et LINQ-to-NHibernate pour vos autres requêtes. Vous pouvez librement mélanger des techniques de requête dans NHibernate.

+0

J'aime cette solution car elle offre une solution non-InMemory qui vous permet également d'utiliser 'typeof' au lieu de Generics. Je n'ai jamais pensé que je finirais par utiliser des critères nHibernate bruts à nouveau! – Holf

Questions connexes