J'utilise JPA dans mon projet.
Je suis arrivé à une requête dans laquelle je dois effectuer une opération de jointure sur cinq tables. J'ai donc créé une requête native qui renvoie cinq champs.
Maintenant, je veux convertir l'objet de résultat en classe java POJO qui contient les cinq mêmes chaînes.
Existe-t-il un moyen dans JPA de convertir directement ce résultat en liste d'objets POJO?
Je suis venu à la solution suivante.
@NamedNativeQueries({
@NamedNativeQuery(
name = "nativeSQL",
query = "SELECT * FROM Actors",
resultClass = db.Actor.class),
@NamedNativeQuery(
name = "nativeSQL2",
query = "SELECT COUNT(*) FROM Actors",
resultClass = XXXXX) // <--------------- problem
})
Maintenant, ici dans resultClass, devons-nous fournir une classe qui est une entité JPA réelle? OU Nous pouvons le convertir en n'importe quelle classe JAVA POJO qui contient les mêmes noms de colonnes?
Réponses:
JPA fournit un
SqlResultSetMapping
qui vous permet de mapper tous les retours de votre requête native dans une entitéou une classe personnalisée.EDIT JPA 1.0 n'autorise pas le mappage vers des classes non-entité. Uniquement dans JPA 2.1, un ConstructorResult a été ajouté pour mapper les valeurs de retour d'une classe java.
En outre, pour le problème de l'OP avec l'obtention du nombre, il devrait être suffisant de définir un mappage d'ensemble de résultats avec un seul
ColumnResult
la source
ConstructorResult
tant que paramètre àSqlResultSetMapping
cela permet d'utiliser un pojo avec tous les champs définis dans le constructeur. Je mettrai à jour la réponse.J'ai trouvé quelques solutions à cela.
Utilisation d'entités mappées (JPA 2.0)
En utilisant JPA 2.0, il n'est pas possible de mapper une requête native à un POJO, cela ne peut être fait qu'avec une entité.
Par exemple:
Mais dans ce cas,
Jedi
,, doit être une classe d'entité mappée.Une alternative pour éviter l'avertissement non coché ici, serait d'utiliser une requête native nommée. Donc, si nous déclarons la requête native dans une entité
Ensuite, nous pouvons simplement faire:
C'est plus sûr, mais nous sommes toujours limités à utiliser une entité mappée.
Cartographie manuelle
Une solution que j'ai expérimentée un peu (avant l'arrivée de JPA 2.1) consistait à faire du mapping contre un constructeur POJO en utilisant un peu de réflexion.
Cette méthode prend essentiellement un tableau de tuple (tel que renvoyé par les requêtes natives) et le mappe sur une classe POJO fournie en recherchant un constructeur qui a le même nombre de champs et du même type.
Ensuite, nous pouvons utiliser des méthodes pratiques telles que:
Et nous pouvons simplement utiliser cette technique comme suit:
JPA 2.1 avec @SqlResultSetMapping
Avec l'arrivée de JPA 2.1, nous pouvons utiliser l'annotation @SqlResultSetMapping pour résoudre le problème.
Nous devons déclarer un mappage d'ensemble de résultats quelque part dans une entité:
Et puis nous faisons simplement:
Bien sûr, dans ce cas,
Jedi
il n'est pas nécessaire d'être une entité mappée. Cela peut être un POJO ordinaire.Utilisation du mappage XML
Je fais partie de ceux qui trouvent que l'ajout de tous ces éléments est
@SqlResultSetMapping
assez invasif dans mes entités, et je n'aime pas particulièrement la définition des requêtes nommées au sein des entités, alors je fais tout cela dans leMETA-INF/orm.xml
fichier:Et ce sont toutes les solutions que je connais. Les deux derniers sont le moyen idéal si nous pouvons utiliser JPA 2.1.
la source
@SqlResultSetMapping
doit être placé dans une entité car c'est à partir de là que JPA va lire les métadonnées. Vous ne pouvez pas vous attendre à ce que JPA inspecte vos POJO. L'entité dans laquelle vous placez le mappage n'est pas pertinente, peut-être celle qui est le plus liée à vos résultats POJO. Alternativement, le mappage pourrait être exprimé en XML pour éviter le couplage avec une entité totalement indépendante.@SqlResultSetMapping
il peut être intéressant de noter que laJedi
classe nécessitera un constructeur all-arg et que l'@ColumnResult
annotation peut nécessiter l'type
ajout de l' attribut aux conversions qui pourraient ne pas être implicites (j'avais besoin d'ajoutertype = ZonedDateTime.class
pour certaines colonnes).Oui, avec JPA 2.1, c'est facile. Vous avez des annotations très utiles. Ils vous simplifient la vie.
Déclarez d'abord votre requête native, puis votre mappage d'ensemble de résultats (qui définit le mappage des données renvoyées par la base de données vers vos POJO). Écrivez votre classe POJO à laquelle vous référer (non incluse ici par souci de concision). Dernier point mais non le moindre: créez une méthode dans un DAO (par exemple) pour appeler la requête. Cela a fonctionné pour moi dans une application dropwizard (1.0.0).
Déclarez d'abord une requête native dans une classe d'entité:
En dessous, vous pouvez ajouter la déclaration de mappage du jeu de résultats:
Plus tard dans un DAO, vous pouvez faire référence à la requête comme
C'est tout.
la source
Si vous utilisez
Spring-jpa
, ceci est un complément aux réponses et à cette question. Veuillez corriger cela en cas de défaut. J'ai principalement utilisé trois méthodes pour obtenir un "résultat de mappageObject[]
vers un pojo" en fonction du besoin pratique que je rencontre:sql
avec sonEntity
suffit.L'ancien 2 a échoué, et je dois utiliser un fichier
nativeQuery
. Voici les exemples. Le pojo attendait:Méthode 1 : changez le pojo en une interface:
Et référentiel:
Méthode 2 : référentiel:
Remarque: la séquence de paramètres du constructeur POJO doit être identique à la fois dans la définition POJO et dans SQL.
Méthode 3 : Utilisez
@SqlResultSetMapping
et@NamedNativeQuery
inEntity
comme exemple dans la réponse d'Edwin Dalorzo.Les deux premières méthodes appelleraient de nombreux gestionnaires intermédiaires, comme des convertisseurs personnalisés. Par exemple,
AntiStealing
définit unsecretKey
, avant qu'il ne soit persistant, un convertisseur est inséré pour le chiffrer. Cela entraînerait les 2 premières méthodes renvoyant un retour convertisecretKey
qui n'est pas ce que je veux. Alors que la méthode 3 surmonterait le convertisseur, et renvoyéesecretKey
serait la même qu'elle est stockée (cryptée).la source
La procédure de déballage peut être effectuée pour attribuer des résultats à une non-entité (qui est Beans / POJO). La procédure est la suivante.
L'utilisation est pour l'implémentation JPA-Hibernate.
la source
JobDTO
devrait avoir le constructeur par défaut. Ou vous pouvez implémenter votre propre transformateur en fonction de l'AliasToBeanResultTransformer
implémentation.Déclarez d'abord les annotations suivantes:
Puis annotez votre POJO comme suit:
Ensuite, écrivez le processeur d'annotations:
Utilisez le cadre ci-dessus comme suit:
la source
BeanUtils
?Le moyen le plus simple est d'utiliser ainsi des projections . Il peut mapper les résultats de la requête directement aux interfaces et est plus facile à implémenter que l'utilisation de SqlResultSetMapping.
Un exemple est présenté ci-dessous:
Les champs de l'interface projetée doivent correspondre aux champs de cette entité. Sinon, le mappage de champ pourrait être interrompu.
De plus, si vous utilisez la
SELECT table.column
notation, définissez toujours des alias correspondant aux noms d'entité comme indiqué dans l'exemple.la source
En veille prolongée, vous pouvez utiliser ce code pour mapper facilement votre requête native.
la source
Utilisation de Hibernate:
la source
Ancien style avec ResultSet
la source
Puisque d'autres ont déjà mentionné toutes les solutions possibles, je partage ma solution de contournement.
Dans ma situation avec
Postgres 9.4
, en travaillant avecJackson
,Je suis sûr que vous pouvez trouver la même chose pour d'autres bases de données.
Aussi FYI, résultats de requêtes natives JPA 2.0 sous forme de carte
la source
Je ne sais pas si cela correspond ici, mais j'avais une question similaire et j'ai trouvé la solution / exemple simple suivante pour moi:
Dans mon cas, j'ai dû utiliser des parties SQL définies dans Strings ailleurs, donc je ne pouvais pas simplement utiliser NamedNativeQuery.
la source
Ancien style à l'aide du jeu de résultats
la source
Nous avons résolu le problème de la manière suivante:
la source
Voir l'exemple ci-dessous pour utiliser un POJO comme pseudo-entité pour récupérer le résultat d'une requête native sans utiliser SqlResultSetMapping complexe. Juste besoin de deux annotations, un @Enity nu et un @Id factice dans votre POJO. @Id peut être utilisé sur n'importe quel champ de votre choix, un champ @Id peut avoir des clés en double mais pas des valeurs nulles.
Puisque @Enity ne correspond à aucune table physique, ce POJO est appelé une pseudo entité.
Environnement: eclipselink 2.5.0-RC1, jpa-2.1.0, mysql-connector-java-5.1.14
Vous pouvez télécharger le projet maven complet ici
La requête native est basée sur les exemples d'employés mysql db http://dev.mysql.com/doc/employee/en/employees-installation.html
persistence.xml
Employee.java
EmployeeNativeQuery.java
la source
list
est, prétendument, une liste deEmployee
, pourquoi votre boucle for-each itère sur un typeObject
? Si vous écrivez votre boucle for-each comme cela,for(Employee emp : list)
vous découvrirez que votre réponse est fausse et que le contenu de votre liste n'est pas des employés et que cet avertissement que vous avez supprimé avait pour but de vous alerter de cette erreur potentielle.List<Employee> list = (List<Employee>) query.getResultList();
Changefor (Object emp : list)
tofor (Employee emp : list)
is better, mais aucune erreur si elle est conservéeObject emp
car la liste est une instance deList<Employee>
. J'ai changé le code dans le projet git mais pas ici pour garder votre commentaire pertinent par rapport à l'article originalQuery query = em.createNativeQuery("select * ...", Employee.class);
et persistence.xml, la requête native renvoie une liste d'employés. Je viens de vérifier et d'exécuter le projet sans problème. Si vous configurez la base de données des exemples d'employés mysql localement, vous devriez également pouvoir exécuter le projetEmployee
ce que je suppose être une entité. N'est-ce pas?si vous utilisez Spring, vous pouvez utiliser
org.springframework.jdbc.core.RowMapper
Voici un exemple:
la source
Utilisation de Hibernate:
la source
Un moyen simple de convertir une requête SQL en collection de classes POJO,
la source
Tout ce dont vous avez besoin est un DTO avec un constructeur:
et appelez-le:
la source
Utilisez
DTO Design Pattern
. Il a été utilisé dansEJB 2.0
. L'entité était gérée par conteneur.DTO Design Pattern
est utilisé pour résoudre ce problème. Mais, il pourrait être utilisé maintenant, lorsque l'application est développéeServer Side
etClient Side
séparément.DTO
est utilisé lorsqueServer side
ne veut pas passer / retournerEntity
avec une annotationClient Side
.Exemple DTO:
PersonEntity.java
PersonDTO.java
DTOBuilder.java
EntityBuilder.java <- il mide be need
la source