2008-11-25 4 views
28

J'essaie d'obtenir des résultats distincts en utilisant l'API Criteria dans NHibernate. Je sais que c'est possible en utilisant HQL, mais je préférerais le faire en utilisant l'API Criteria, parce que le reste de mon application est écrit en utilisant seulement cette méthode. Je found this forum post, mais je n'ai pas réussi à le faire fonctionner. Y a-t-il un moyen avec l'API de critères d'obtenir des ensembles de résultats distincts? Edit: En faisant cela, je voulais également exclure la colonne Primary Key, qui est aussi une identité, et obtenir les enregistrements distincts restants. Y a-t-il un moyen de faire cela? En l'état, les enregistrements distincts renvoient des doublons car la clé primaire est unique pour chaque ligne, mais tous les autres champs sont identiques.Obtenir un jeu de résultats distinct à partir de NHibernate à l'aide de l'API Criteria?

Répondre

23

ne peut pas voir le post sur le forum à ce moment, alors peut-être ce n'est pas la réponse, mais vous pouvez ajouter un DistinctRootEntityResultTransformer (lien cassé?):

session.CreateCriteria(typeof(Product) 
    .Add(...) 
    .SetResultTransformer(new DistinctEntityRootTransformer()) 
+0

Ok, je n'ai jamais fait ça avant, donc une question rapide. J'ai une clé primaire, qui est un champ d'identité. Comment puis-je exclure ce champ de l'ensemble de résultats afin que les résultats distincts soient vraiment distincts? Je peux préciser si cela n'a pas de sens. –

+0

Je ne sais pas si c'est possible. Vous pourriez créer un DTO avec les autres champs et interroger ce DTO, mais il faudrait utiliser hql. – Juanma

+0

D'où provient DistinctEntityRootTransformer? VS ne le résoudra pas pour moi. Est-ce que je manque une assemblée quelque part? – BuddyJoe

86

Pour effectuer une requête distincte, vous pouvez définir la projection sur les critères aux projections.Distinct. Vous incluez ensuite les colonnes que vous souhaitez retourner. Le résultat est ensuite retourné dans un objet fortement typé en définissant le transformateur de résultat à AliasToBeanResultTransformer - en passant le type dans lequel le résultat doit être transformé. Dans cet exemple, j'utilise le même type que l'entité elle-même, mais vous pouvez créer une autre classe spécifiquement pour cette requête.

ICriteria criteria = session.CreateCriteria(typeof(Person)); 
criteria.SetProjection(
    Projections.Distinct(Projections.ProjectionList() 
     .Add(Projections.Alias(Projections.Property("FirstName"), "FirstName")) 
     .Add(Projections.Alias(Projections.Property("LastName"), "LastName")))); 

criteria.SetResultTransformer(
    new NHibernate.Transform.AliasToBeanResultTransformer(typeof(Person))); 

IList<Person> people = criteria.List<Person>(); 

Cela crée SQL similaire à (dans SQL Server au moins):

SELECT DISTINCT FirstName, LastName from Person 

S'il vous plaît noter que seuls les propriétés que vous spécifiez dans votre projection seront renseignés dans le résultat.

L'avantage de cette méthode est que le filtrage est effectué dans la base de données plutôt que de renvoyer tous les résultats à votre application, puis d'effectuer le filtrage, qui est le comportement de DistinctRootEntityTransformer.

+0

Savez-vous comment je pourrais hydrater le graphique de l'objet enfant? Je peux l'obtenir pour sélectionner toutes les colonnes de la racine, y compris les colonnes de clé étrangère, mais je ne sais pas comment l'obtenir pour les charger après le retour de la requête. – longday

+0

@longday Je ne pense pas qu'il soit possible d'avoir NHibernate parce qu'en faisant une projection distincte, vous n'avez plus affaire à des entités réelles (même si vous réutilisez la même classe). Ce que vous pouvez faire est d'inclure des colonnes de plusieurs tables dans votre projection et de créer une classe distincte à utiliser dans le résultat qui a toutes les propriétés qui vous intéressent. –

+0

Cela ne fonctionne pas si vous avez défini un alias dans les critères, parce qu'il commencera alors à regarder l'alias parmi les membres de la classe, qu'il ne peut bien sûr pas trouver. –

-4

J'ai également rencontré le problème du nombre d'éléments non distincts (j'utilise un fetch = "join" dans mon fichier de mapping). Je Linq Pour Nhibernate pour résoudre le problème, qui est utilisé de la manière suivante:

 var suppliers = (from supplier in session.Linq<Supplier>() 
         from product in supplier.Products 
         where product.Category.Name == produtCategoryName 
         select supplier).ToList().Distinct(); 
+9

Incorrect. Le Distinct dans ce cas se fait côté client. Vous appelez ToList(), qui renvoie tous les résultats. Regardez dans NHProf. –

+0

SetResultTransformer (new DistinctEntityRootTransformer()) dans la réponse http://stackoverflow.com/questions/318157/get-distinct-result-set-from-nhibernate-using-criteria-api/318196#318196 fait presque la même chose que. Distinct(). Ils sont tous deux des transformations côté client. Et ils sont presque équivalents. –

-1

Nous utilisons les moyens les plus modernes et puissants et impressionnante minuscules de tout gérer cela ... lire seulement si vous « re préparé pour le génial ... et il n'a rien à voir avec des critères ...

CurrentSession() 
    .QueryOver<GoodBadAndUgly> 
    .Where(...) 
    .TransformUsing(Transformers.DistinctRootEntity) 

donc, si vous êtes ici dans l'espoir d'une façon de faire qui vous a éviter de jouer avec les critères même bien que vous pensiez que vous deviez absolument aller dans cette direction juste pour ajouter 'DISTINCT' dans votre SQL ... recherche pas plus loin

Questions connexes