Requête Hibernate Par Exemple et Projections
-
01-07-2019 - |
Question
En résumé: hibernate ne prend pas en charge les projections et les requêtes par exemple? J'ai trouvé ce post:
Le code est le suivant:
User usr = new User();
usr.setCity = 'TEST';
getCurrentSession().createCriteria(User.class)
.setProjection( Projections.distinct( Projections.projectionList()
.add( Projections.property("name"), "name")
.add( Projections.property("city"), "city")))
.add( Example.create(usr))
Comme l’a dit l’autre affiche, sql généré continue d’avoir une classe where se référant à y0_ =? au lieu de this_.city .
J'ai déjà essayé plusieurs approches et cherché dans l'outil de suivi des problèmes, mais rien trouvé à ce sujet.
J'ai même essayé d'utiliser l'alias de projection et les transformateurs, mais cela ne fonctionne pas:
User usr = new User();
usr.setCity = 'TEST';
getCurrentSession().createCriteria(User.class)
.setProjection( Projections.distinct( Projections.projectionList()
.add( Projections.property("name"), "name")
.add( Projections.property("city"), "city")))
.add( Example.create(usr)).setResultTransformer(Transformers.aliasToBean(User.class));
Quelqu'un at-il utilisé des projections et des requêtes par exemple?
La solution
Puis-je voir votre classe d'utilisateurs? Ceci est juste en utilisant les restrictions ci-dessous. Je ne vois pas pourquoi les restrictions seraient vraiment différentes des exemples (je pense cependant que les champs nuls sont ignorés par défaut dans les exemples).
getCurrentSession().createCriteria(User.class)
.setProjection( Projections.distinct( Projections.projectionList()
.add( Projections.property("name"), "name")
.add( Projections.property("city"), "city")))
.add( Restrictions.eq("city", "TEST")))
.setResultTransformer(Transformers.aliasToBean(User.class))
.list();
Je n'ai jamais utilisé alaistToBean, mais je viens de lire à ce sujet. Vous pouvez également simplement parcourir les résultats.
List<Object> rows = criteria.list();
for(Object r: rows){
Object[] row = (Object[]) r;
Type t = ((<Type>) row[0]);
}
Si vous devez le faire, vous pouvez renseigner manuellement l'utilisateur vous-même de cette façon.
Il est difficile d'examiner le problème sans disposer de plus d'informations pour le diagnostiquer.
Autres conseils
Le problème semble se produire lorsque vous avez un alias du même nom que la propriété objects. Hibernate semble prendre l'alias et l'utiliser dans le sql. J'ai trouvé cette documentation ici et ici , et moi crois que c’est un bug d’Hibernate, même si je ne suis pas sûr que l’équipe d’Hibernate soit d’accord.
De toute façon, j’ai trouvé un moyen simple de contourner le problème. Votre kilométrage peut varier. Les détails sont ci-dessous, j'ai essayé de simplifier le code pour cet exemple, donc je m'excuse pour les erreurs ou les fautes de frappe:Criteria criteria = session.createCriteria(MyClass.class)
.setProjection(Projections.projectionList()
.add(Projections.property("sectionHeader"), "sectionHeader")
.add(Projections.property("subSectionHeader"), "subSectionHeader")
.add(Projections.property("sectionNumber"), "sectionNumber"))
.add(Restrictions.ilike("sectionHeader", sectionHeaderVar)) // <- Problem!
.setResultTransformer(Transformers.aliasToBean(MyDTO.class));
Produirait ce sql:
select
this_.SECTION_HEADER as y1_,
this_.SUB_SECTION_HEADER as y2_,
this_.SECTION_NUMBER as y3_,
from
MY_TABLE this_
where
( lower(y1_) like ? )
Qui a provoqué une erreur: java.sql.SQLException: ORA-00904: "Y1_": identificateur non valide
Mais, lorsque j'ai modifié ma restriction, elle a été utilisée de la manière suivante:
Criteria criteria = session.createCriteria(MyClass.class)
.setProjection(Projections.projectionList()
.add(Projections.property("sectionHeader"), "sectionHeader")
.add(Projections.property("subSectionHeader"), "subSectionHeader")
.add(Projections.property("sectionNumber"), "sectionNumber"))
.add(Restrictions.ilike("this.sectionHeader", sectionHeaderVar)) // <- Problem Solved!
.setResultTransformer(Transformers.aliasToBean(MyDTO.class));
Cela a produit le code SQL suivant et mon problème a été résolu.
select
this_.SECTION_HEADER as y1_,
this_.SUB_SECTION_HEADER as y2_,
this_.SECTION_NUMBER as y3_,
from
MY_TABLE this_
where
( lower(this_.SECTION_HEADER) like ? )
C’est ça! Une solution assez simple à un problème douloureux. Je ne sais pas comment ce correctif résoudrait le problème requête par exemple, mais cela pourrait vous rapprocher.
Le vrai problème ici est qu'il existe un bogue dans hibernate qui utilise des alias de liste de sélection dans la clause where:
http://opensource.atlassian.com/projects/hibernate/browse/ HHH-817
Juste au cas où quelqu'un atterrirait ici à la recherche de réponses, allez voir le billet. Cela a pris 5 ans pour résoudre le problème, mais en théorie ce sera dans l’une des prochaines versions et ensuite, je suppose que votre problème disparaîtra.
Je suis confronté à un problème similaire. J'utilise une requête par exemple et je souhaite trier les résultats selon un champ personnalisé. En SQL, je ferais quelque chose comme:
select pageNo, abs(pageNo - 434) as diff
from relA
where year = 2009
order by diff
Cela fonctionne très bien sans ordre par clause. Ce que j'ai obtenu est
Criteria crit = getSession().createCriteria(Entity.class);
crit.add(exampleObject);
ProjectionList pl = Projections.projectionList();
pl.add( Projections.property("id") );
pl.add(Projections.sqlProjection("abs(`pageNo`-"+pageNo+") as diff", new String[] {"diff"}, types ));
crit.setProjection(pl);
Mais quand j'ajoute
crit.addOrder(Order.asc("diff"));
Je reçois une exception org.hibernate.QueryException: impossible de résoudre la propriété: diff . La solution de contournement avec this ne fonctionne pas non plus.
PS: je n’ai trouvé aucune documentation détaillée sur l’utilisation de QBE pour Hibernate, tout ce qui est décrit ci-dessus est principalement une approche empirique
ProjectionList pl = Projections.projectionList();
pl.add(Projections.property("id"));
pl.add(Projections.sqlProjection("abs(`pageNo`-" + pageNo + ") as diff", new String[] {"diff"}, types ), diff); ---- solution
crit.addOrder(Order.asc("diff"));
crit.setProjection(pl);
Je ne le pense pas vraiment. Ce que je peux trouver, c’est le mot "ceci". veille à ce que l'hibernation n'inclue aucune restriction dans sa requête, ce qui signifie qu'il a toutes les listes d'enregistrements. À propos du bogue de veille prolongée qui a été signalé, je peux voir qu’il a été corrigé mais j’ai totalement échoué dans le téléchargement du correctif.