NHibernate Criteria with Distinct Parent Load All

2020-04-23 03:39发布

I have a parent child relationship where I want to return only one parent and load all the children. I am using criteria because it is a dynamic query.

var messageQueueId = this.GetPropertyName<MessageQueue>(x => x.Id);

var query = _sessionManager.Session.CreateCriteria<MessageQueue>(QUEUE_ALIAS);

query.SetFirstResult(_pageOffset);
query.SetMaxResults(_pageSize);
query.Add(Restrictions.In(messageQueueId, _messageQueueIds));

query.List<MessageQueue>();

This returns the parent (MessageQueue) but not it's children (SearchMatches).

When I try to do this:

var query = _sessionManager.Session
    .CreateCriteria<MessageQueue>(QUEUE_ALIAS)
    .CreateAlias(this.GetPropertyName<MessageQueue>(x => x.SearchMatches)
                , MATCH_ALIAS, JoinType.LeftOuterJoin);

Then I get the children loaded, but also I receive duplicate parents. I understand why this is happening. However I don't understand how to get the first scenario to just load the SearchMatches automatically?

Here are my entitites:

public class MessageQueue : EntityBase
{
    ...
    public virtual IList<SearchMatch> SearchMatches { get; set; }
    ...
}

public class SearchMatch : EntityBase
{
    ...
    public virtual MessageQueue MessageQueue { get; set; }
    ...
}

Fluent NHibernate is set to DefaultCascade.All(). I have no other overrides for these objects.

I have tried to use Inverse() and Not.LazyLoad() off of the MessageQueue override. Also Tried to EagerLoad off the CreateAlias. But I am still not getting what I need back.

1条回答
够拽才男人
2楼-- · 2020-04-23 04:10

I would suggest to use the batch-size="" setting. It will end up in
1) one query issued by us (query.List<MessageQueue>();),
2) NHibernate will use then one (or just few) query/ies to load collection for each returned MessageQueue.

19.1.5. Using batch fetching

NHibernate can make efficient use of batch fetching, that is, NHibernate can load several uninitialized proxies if one proxy is accessed (or collections. Batch fetching is an optimization of the lazy select fetching strategy. There are two ways you can tune batch fetching: on the class and the collection level.

Batch fetching for classes/entities is easier to understand. Imagine you have the following situation at runtime: You have 25 Cat instances loaded in an ISession, each Cat has a reference to its Owner, a Person. The Person class is mapped with a proxy, lazy="true". If you now iterate through all cats and call cat.Owner on each, NHibernate will by default execute 25 SELECT statements, to retrieve the proxied owners. You can tune this behavior by specifying a batch-size in the mapping of Person:

<class name="Person" batch-size="10">...</class>

The fluent alternative is (both collection and class level)

.BatchSize(25)

Also check:

NOTE: At the end, the number passed as a batch size, e.g. 25, seems to be used as its half - 12. So if you do paging on a size of 25, try to use SetBatchSize(50)

查看更多
登录 后发表回答