Description
visubesy created an issue — 20th May 2016, 16:48:08:
Problem
EntityLoader doesn't override the property Loader.IsSubselectLoadingEnabled. That means that NHibernate won't generate subselects even if they were configured in the mapping. This can lead to performance problems (N+1 problem).
Remark: The property Loader.IsSubselectLoadingEnabled is processed in Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, bool returnProxies, IResultTransformer forcedResultTransformer).
Possible solution
Override Loader.IsSubselectLoadingEnabled in EntityLoader by calling Loader.HasSubselectLoadableCollections(). This is already done by CriteriaLoader, QueryLoader and CollectionLoader.
I don't know if this could produce any unwanted side-effects.
Example (Fluent NHibernate)
If the Abc instances are loaded by NHibernate using batch fetching, there won't be a single SELECT with subselect for the AbcArraySize instances. Instead there will be one SELECT for each ArraySize instance.
public class AbcMap : ClassMap<Abc> { public AbcMap() { // ... BatchSize(640); HasMany(x => x.ArraySizes).KeyColumn(AbcArraySizeMap.ColumnAbcId) .CollectionType<MyListType<AbcArraySize>>() .ReadOnly() .Cascade.Evict() .Not.KeyNullable().Not.KeyUpdate() .Inverse() .Fetch.Subselect() .Not.LazyLoad(); } } public class AbcArraySizeMap : ClassMap<AbcArraySize> { internal const string ColumnAbcId = "ABC_ID"; public AbcArraySizeMap() { // ... } }
Workaround (well, not really)
One can add a call to BatchSize in the above HasMany mapping. There still won't be a subselect as intended but at least the generated SELECTs for AbcArraySize will use batch fetching.
visubesy added a comment — 20th May 2016, 16:54:48:
In the above description, it should read "Instead there will be several SELECTs to load the AbcArray instances, one for each Abc instance" instead of "Instead there will be one SELECT for each ArraySize instance". I can't edit the description.