2010-02-17 11 views
3

Ceci est la configuration de mes 2 entités:NHibernate: critères de requête pour une entité et peut-être une sous-classe dans la même requête

public class Person { 
    public Guid Id {get;set;} 
    public string Name {get;set;} 
} 

public class Immortal : Person { 
    public string DarkName {get;set;} 
} 

Voici ce que leurs applications ressemblent:

<class name="Person"> 
    <id name="Id"> 
    <generator class="guid.comb"/> 
    </id> 
    <property name="Name" /> 

    <joined-subclass name="Immortal"> 
    <key column='PersonId' /> 
    <property name="DarkName" /> 
    </joined-subclass> 
</class> 

Alors c'est la configuration, 2 entités, l'une est une sous-classe jointe de l'autre. J'ai un cadre de recherche qui prend un certain nombre de critères d'un formulaire, puis applique les critères appropriés à une requête, puis renvoie les résultats. Maintenant, disons que j'ai un seul champ de formulaire dans ce cas, "Nom" - Je veux ramener tous les gens, qu'ils soient des personnes normales ou cette classe spéciale d'êtres Immortels, en voyant si leur nom correspond à la propriété Nom de Person, mais dans le cas d'un Immortel, j'aimerais aussi le compter comme un match si leur DarkName correspond à ce qui a été donné dans le formulaire.

Alors c'est mon dilemme, comment je fais ça? Le mieux que j'ai pu faire avec ICriteria de NHibernate est de faire une sous-requête sur Immortal pour vérifier le nom, puis voir si l'identifiant de la personne racine est dans cette sous-requête. Cependant, lorsque l'on travaille avec une table de 10 ou de milliers de personnes, cette méthode d'obtention de résultats est extraordinairement inefficace et peut même temporiser la demande (30+) dans ma situation réelle.

Je serais ouvert à faire cela aussi en HQL, parce que je veux une jointure externe sur Immortal pour vérifier ce champ, mais je ne peux pas obtenir une jointure de HQL sur 2 entités disparates sur une propriété arbitraire - joint autant que je sache doit être basé sur des associations directes dans vos cartographies. Par exemple, voici ce que je comme voir:

select person from Person person 
    outer join Immortal immortal on immortal.PersonId = person.Id 
    where 
    person.Name = :name or 
    immortal.DarkName = :name 

Que dites-vous Stackoverflow?

+1

Montrez-nous vos correspondances. NHibernate supporte les requêtes polymorphes, mais l'as-tu cartographié comme tel? –

+0

Ok, je l'ai ajouté. –

Répondre

3

La requête critères suivante produit presque exactement le SQL que vous souhaitez.

Il tire parti de laxisme dans le moteur de recherche de critères.

var list = session.CreateCriteria<Person>() 
    .Add(Expression.Disjunction() 
     .Add(Expression.Eq("Name", name)) 
     .Add(Expression.Eq("ImmortalName", name)) 
     ) 
    .List<Person>(); 

produit l'instruction SQL suivante:

SELECT this_.Id    as Id0_0_, 
     this_.Name   as Name0_0_, 
     this_1_.ImmortalName as Immortal2_1_0_, 
     case 
     when this_1_.Id is not null then 1 
     when this_.Id is not null then 0 
     end as clazz_0_ 
FROM person this_ 
     left outer join immortal this_1_ 
     on this_.Id = this_1_.Id 
WHERE (this_.Name = 'foo' /* @p0 */ 
     or this_1_.ImmortalName = 'foo' /* @p1 */) 

J'ai utilisé la cartographie de classe suivante:

<class name="Person" table="person"> 
    <id name="Id"> 
     <generator class="identity" /> 
    </id> 
    <property name="Name" /> 
    <joined-subclass name="Immortal" table="immortal"> 
     <key column="Id" /> 
     <property name="ImmortalName" /> 
    </joined-subclass> 
</class> 
+0

J'ai lutté avec un problème similaire au cours des dernières heures. Expression.Disjunction était exactement ce dont j'avais besoin. Merci! – csano