NHibernate: can't successfully set lazy loading
-
20-08-2019 - |
Question
I have a table Parent and a table Child. Child contains a foreign-key to the Parent table, creating a one-to-many relationship. Here is a part of my mapping that I define with fluent NHibernate:
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();
}
}
As you can see I have set LazyLoad on the relation. Note also that in my model classes, all properties are set as virtual.
Now for the simple query:
ICriteria crit = Session.CreateCriteria(typeof(Child))
.Add(Expression.Eq("Id", 18));
IList<Child> list = crit.List<Child>();
And the SQL generated:
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 */
As you can see, it does a join on the Parent table and selects its fields (id and description). But why does it do that since I requested lazyloading ?
Now if I change the query to:
ICriteria crit2 = Session.CreateCriteria(typeof(Child))
.SetFetchMode("Parent", FetchMode.Lazy)
.Add(Expression.Eq("Id", 18));
There are 2 sql queries generated:
SELECT this_.ChildID as ChildID5_0_,
this_.ParentID as ParentID5_0_
FROM Childs this_
WHERE this_.ChildID = 18 /* @p0 */
which is good to me: no join, the Parent table is not queried. But I get this second one too:
SELECT parent0_.ParentID as ParentID4_0_,
parent0_.Description as Descript2_4_0_
FROM Parents parent0_
WHERE parent0_.ParentID = 45 /* @p0 */
which again queries the Parent table.
These 2 queries are generated during the line:
IList<Child> list = crit.List<Child>();
I'm totally ignorant of what happens here. Can someone help?
Solution
It'll depend on your version of Fluent NHibernate. Up until a certain point it was the default that all entities would not be lazy loaded. This is the equivalent of explicitly setting lazy="false"
in your entity. This is no longer the case, but if you are running on anything prior to that point then you'll see this behaviour.
The many-to-one/references lazy load setting gets overridden by the entity level lazy load from the target, so if you are running on this older version of FNH then the entity setting will be rendering your References(...).LazyLoad()
call moot.
You need to verify you're on the latest version of FNH, that should fix things; however, if it doesn't then you need to explicitly set lazy loading on in your Parent
entity. You can do that with the LazyLoad
method on the ClassMap<T>
.