(Se sentait assez impuissant dans la formulation d'un titre approprié...)
Est-il possible de définir un mapping pour une classe de telle sorte que certaines propriétés soient récupérées depuis une autre table en utilisant une requête de jointure ?
Dans mon application C#, j'affiche une liste d'objets "A", ainsi que certaines propriétés de leurs objets "B" associés et des propriétés des objets "C" associés à B :
A.Name B.Name B.SomeValue C.Name
Foo Bar 123 HelloWorld
Bar Hello 432 World
...
Pour clarifier : A a une clé étrangère vers B, B a une clé étrangère vers C. (Comme par exemple, CompteBancaire -> Personne -> Entreprise).
Si j'étends la classe A avec des propriétés "BName", "BSomeValue" et "CName", est-il possible de faire en sorte que [N]Hibernate émette une requête comme
select A.Name, B.Name as BName, B.SomeValue as BSomeValue, C.Name as CName
from A
join B on A.B_ID = B.ID
join C on B.C_ID = C.ID
et de mapper tous les résultats de cette requête sur les propriétés de A ?
Contexte :
J'ai essayé deux approches pour charger ces propriétés depuis la base de données (en utilisant NHibernate) : une approche rapide et une approche propre. Ma question finale est comment faire une approche rapide et propre.
Approche rapide :
- Définir une vue dans la base de données qui joint A, B, C et fournit tous ces champs.
- Dans la classe A, définir les propriétés "BName", "BSomeValue", "CName"
- Définir un mapping Hibernate entre A et la Vue, alors que les propriétés nécessaires de B et C sont mappées avec
update="false" insert="false"
et proviennent en réalité des tables B et C, mais Hibernate n'en est pas conscient car il utilise la vue.
De cette façon, la liste ne charge qu'un seul objet par enregistrement "A", ce qui est assez rapide. Si le code essaie d'accéder à la propriété associée réellement, "A.B", j'émet une autre requête HQL pour obtenir B, définir la propriété et mettre à jour les propriétés simulées BName et BSomeValue également.
Approche propre :
- Il n'y a pas de vue.
- La classe A est mappée sur la table A, B sur B, C sur C.
- Lors du chargement de la liste de A, je fais un double left-join-fetch pour obtenir B et C également :
from A a left join fetch a.B left join fetch a.B.C
- B.Name, B.SomeValue et C.Name sont accessibles via les associations chargées en avance.
L'inconvénient de cette approche est qu'elle devient plus lente et nécessite plus de mémoire, car elle doit créer et mapper 3 objets par enregistrement "A" : un objet A, B et C chacun.
Approche rapide et propre :
Je me sens quelque peu mal à l'aise d'utiliser une vue de base de données qui masque une jointure et de traiter cela dans NHibernate comme s'il s'agissait d'une table. Donc j'aimerais faire quelque chose comme :
- Ne pas avoir de vues dans la base de données.
- Déclarer les propriétés "BName", "BSomeValue", "CName" dans la classe "A".
- Définir le mapping pour A de telle sorte que NHibernate récupère A et ces propriétés ensemble en utilisant une requête SQL de jointure comme le ferait une vue de base de données.
- Le mapping devrait toujours permettre de définir des associations many-to-one paresseuses pour récupérer A.B.C
Mes questions :
- Est-ce possible ?
- Est-ce [in]habile ?
- Y a-t-il une meilleure façon ?