NHibernate: impossible de configurer avec succès le chargement paresseux
-
20-08-2019 - |
Question
J'ai une table Parent et une table Child. Child contient une clé étrangère dans la table Parent, créant une relation un à plusieurs. Voici une partie de ma cartographie que je définis avec NHibernate couramment:
public class ParentMap : ClassMap<Parent>
{
public ParentMap()
{
WithTable("Parents");
Id(x => x.Id, "ParentID")
.WithUnsavedValue(0)
.GeneratedBy.Identity();
Map(x => x.Description, "Description");
HasMany<Child>(x => x.Childs)
.LazyLoad()
.WithKeyColumn("ParentID")
.IsInverse()
.AsSet();
}
}
public class ChildMap : ClassMap<Child>
{
public ChildMap()
{
WithTable("Childs");
Id(x => x.Id, "ChildID")
.WithUnsavedValue(0)
.GeneratedBy.Identity();
References(x => x.Parent, "ParentID")
.CanNotBeNull()
.LazyLoad();
}
}
Comme vous pouvez le constater, j'ai défini LazyLoad sur la relation. Notez également que dans mes classes de modèle, toutes les propriétés sont définies comme virtuelles.
Maintenant pour la requête simple:
ICriteria crit = Session.CreateCriteria(typeof(Child))
.Add(Expression.Eq("Id", 18));
IList<Child> list = crit.List<Child>();
Et le SQL généré:
SELECT this_.ChildID as ChildID5_1_,
this_.ParentID as ParentID5_1_,
parent2_.ParentID as ParentID4_0_,
parent2_.Description as Descript2_4_0_
FROM Childs this_
inner join Parents parent2_
on this_.ParentID = parent2_.ParentID
WHERE this_.ChildID = 18 /* @p0 */
Comme vous pouvez le constater, il effectue une jointure sur la table parent et sélectionne ses champs (id et description). Mais pourquoi fait-il cela depuis que j'ai demandé du lazyloading?
Maintenant si je change la requête en:
ICriteria crit2 = Session.CreateCriteria(typeof(Child))
.SetFetchMode("Parent", FetchMode.Lazy)
.Add(Expression.Eq("Id", 18));
Deux requêtes SQL ont été générées:
SELECT this_.ChildID as ChildID5_0_,
this_.ParentID as ParentID5_0_
FROM Childs this_
WHERE this_.ChildID = 18 /* @p0 */
ce qui est bon pour moi: pas de jointure, la table Parent n’est pas interrogée. Mais je reçois aussi le second:
SELECT parent0_.ParentID as ParentID4_0_,
parent0_.Description as Descript2_4_0_
FROM Parents parent0_
WHERE parent0_.ParentID = 45 /* @p0 */
qui interroge à nouveau la table parent.
Ces 2 requêtes sont générées pendant la ligne:
IList<Child> list = crit.List<Child>();
Je suis totalement ignorant de ce qui se passe ici. Quelqu'un peut-il aider?
La solution
Cela dépend de votre version de Fluent NHibernate. Jusqu'à un certain point, il était par défaut que toutes les entités ne ne soient pas chargées paresseuses. Cela équivaut à définir explicitement lazy="false"
dans votre entité. Ce n'est plus le cas, mais si vous utilisez une version antérieure à cette étape, vous constaterez ce problème.
Le paramètre de chargement paresseux plusieurs-à-un / références est remplacé par le chargement paresseux au niveau de l'entité depuis la cible. Par conséquent, si vous utilisez cette ancienne version de FNH, le paramètre d'entité rendra votre References(...).LazyLoad()
appel moot .
Vous devez vérifier que vous utilisez la dernière version de FNH, ce qui devrait résoudre le problème. Cependant, si ce n'est pas le cas, vous devez définir explicitement le chargement différé dans votre entité Parent
. Vous pouvez le faire avec la méthode LazyLoad
sur le ClassMap<T>
.