web-dev-qa-db-fra.com

Comment mapper au mieux les résultats d'une requête SQL sur un objet Java non-entité à l'aide d'Hibernate?

J'ai une entité Java gérée par Hibernate appelée X et une fonction SQL native (myfunc) que j'appelle à partir d'une requête SQL Hibernate selon ces lignes:

SQLQuery q = hibernateSession.createSQLQuery(
                     "SELECT *, myfunc(:param) as result from X_table_name"
             );

Ce que je veux faire est de mapper tout ce qui est renvoyé par cette requête à une classe (non nécessairement gérée par Hibernate) appelée Y. Y doit contenir tous les propriétés/champs de X plus la result renvoyée par myfunc, par exemple. Y pourrait étendre la classe X et ajouter un champ "résultat".

Ce que j'ai essayé

  1. J'ai essayé d'utiliser q.addEntity(Y.class) mais cela échoue avec: org.hibernate.MappingException: Unknown entity com.mycompany.Y
  2. q.setResultTransformer(Transformers.aliasToBean(Y.class)); mais cela échoue avec: org.hibernate.PropertyNotFoundException: Could not find setter for some_property. X a un champ appelé someProperty avec le getter et le setter appropriés, mais dans ce cas, il ne semble pas que Hibernate mappe le nom de la colonne (propriété_quelque_) vers le nom de champ correct.
  3. q.setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP); renvoie une mappe mais les valeurs ne sont pas toujours du type attendu par le champ correspondant dans X. Par exemple, les champs dans X de type énuméré et Date ne peuvent pas être mappés directement à partir de la mappe renvoyée par la requête SQL (où ils sont des chaînes).

Quelle est la manière appropriée de gérer cette situation?

17
Johan

Voir le chapitre de la documentation sur les requêtes SQL .

Vous pouvez utiliser la méthode addScalar() pour spécifier le type que Hibernat doit utiliser pour une colonne donnée.

Et vous pouvez utiliser des alias pour mapper les résultats avec les propriétés du bean:

select t.some_property as someProperty, ..., myfunc(:param) as result from X_table_name t

Ou bien (et bien que cela nécessite quelques lignes de code, c'est ma solution préférée), vous pouvez simplement faire le mappage vous-même:

List<Object[]> rows = query.list();
for (Object[] row : rows) {
    Foo foo = new Foo((Long) row[0], (String) row[1], ...);
}

Cela évite la réflexion et vous permet de tout contrôler.

16
JB Nizet

Facile. Convertissez les lignes en Map<String, Object>

final org.hibernate.Query q = session.createSQLQuery(sql);
q.setParameter("geo", geo);
q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
final List<Map<String, Object>> src = q.list();
final List<VideoEntry> results = new ArrayList<VideoEntry>(src.size());
for (final Map<String, Object> map:src) {
    final VideoEntry entry = new VideoEntry();
    BeanUtils.populate(entry, map);
    results.add(entry);
}
7
Stan Sokolov

Tout d’abord, vous devez déclarer l’entité dans le fichier xml de configuration hibernate, par exemple: ..... Class = "chemin de votre entité"

Ou vous pouvez faire la même chose par programme avant de faire la requête.

0
Popa Andrei