NHibernate: can't successfully set lazy loadin

2019-02-20 02:38发布

问题:

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?

回答1:

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>.