Does anyone know why I'm getting this warning from NHibernate/NH Profiler?

608 Views Asked by At

"Disabled lazy properies fetching for fully_qualified_type_name beacuse it does not support lazy at the entity level".

This warning was reported by NH Profiler, and as a result, I'm experiencing the dreaded SELECT N + 1 side affect. So if 2200 Subgroup entities are returned, an additional query is being executed to retrieve each InvoicePreference entity (2201 queries total). Something about that relationship seems to be causing the issue.

Here are the entities in question and their respective mappings.

Entity 1

public class Subgroup : Entity
{
     public virtual string GroupNumber { get; set; }

     public virtual string RUSNumber { get; set; }

     public virtual string REANumber { get; set; }

     public virtual string CustomerType { get; set; }

     public virtual string Name { get; set; }

     public virtual IList<IndividualEmployment> Employees { get; set; }

     public virtual IList<BenefitsAdministrator> Administrators { get; set; }

     public virtual InvoicePreference InvoicePreference { get; set; }
}

Entity 2

public class InvoicePreference : IEntity
{
    public virtual Guid Id { get; set; }

    public virtual Guid SubgroupId { get; set; }

    public virtual bool PaperlessNotifications { get; set; }
}

Mapping 1

public static AutoPersistenceModel ConfigureSubGroup(this AutoPersistenceModel 
autoPersistenceModel)
{
    return autoPersistenceModel.Override<Subgroup>(map =>
    {
        map.Table("SubgroupV");

        map.Id(s => s.Id).Column(SubGroupPrimaryKeyColumn);

        map.Map(s => s.CustomerType, "BAS_Customer_Type");
        map.Map(s => s.RUSNumber, "BAS_RUS_Number");
        map.Map(s => s.GroupNumber, "BAS_Group_Number");
        map.Map(s => s.REANumber, "BAS_REA_Number");

        map.HasMany(s => s.Administrators).KeyColumn(SubGroupPrimaryKeyColumn);
        map.HasMany(s => s.Employees).KeyColumn(SubGroupPrimaryKeyColumn);
        map.HasOne(s => s.InvoicePreference).PropertyRef(i => i.SubgroupId);
    });
}

Mapping 2

public static AutoPersistenceModel ConfigureInvoicePreference(this AutoPersistenceModel autoPersistenceModel)
{
    return autoPersistenceModel.Override<InvoicePreference>(map =>
    {
        map.Table("SubgroupInvoicePreference");
        map.Schema(RetirementStatementsSchemaName);
    });
}
2

There are 2 best solutions below

5
On

InvoicePreference is referenced as hasone. Since it is lazyloaded by default NHibernate will create a proxy to populate the property InvoicePreference and to do that it needs the identity from InvoicePreference which is not present in the Subgroup. Therefor it has to query for it using the property in the propertyref.

To remedy that do .Not.LazyLoad() and/or .Fetch.Join()

3
On

I guess that there is some reason why NH disabled lazy loading "on entity level", which I understand as not creating proxies. There may be several reasons for that. Did you get another warning before? I don't really understand why it disabled "lazy properies", which means that some properties are lazy loaded. This is a feature that is used in the mapping explicitly, but I can't see something like this in your mapping definitions.

To overcome the N+1, you may use Fetch.Join. I had bad experience with that, because the queries get really large. In a complex model, you could hit some database server limits (like max. number of columns of a query). It is mostly better to use batch size, which reduces the number of queries notably. Take a look at my answer to "Nhinerbate lazy loading of reference entity".