NHibernate: Select one to Many Left Join - Take X latest from Parent

人盡茶涼 提交于 2019-12-17 21:59:59

问题


I have the following objects:

Parent
   public virtual Guid Id { get; set; }
   public virtual DateTime TimeStamp { get; set; }
   public virtual IList<Child> Childs { get; set; }

Child
   public virtual Guid Id { get; set; }
   public virtual string Name { get; set; }

I use Fluent to Map One To Many as follows:

.Override<Parent>(obj =>obj.HasMany(x => x.Childs)
                                .Cascade.All()
                                .Not.Inverse()
                                .Not.KeyNullable()
                                .Not.KeyUpdate())

I need to get up to all Parent with Childs between dates order by TimeStamp.

I am trying to do it as follows (maxCapacity is int):

QueryOver<Parent>().Where(x => x.TimeStamp > from)
            .And(x => x.TimeStamp < to).OrderBy(x => x.TimeStamp).Desc
            .Left.JoinQueryOver<Child>(x => x.Childs)
            .TransformUsing(new DistinctRootEntityResultTransformer())
            .Take(maxCapacity).List();

The result is not what I expected since the Take(maxCapacity) is not on the parent result but on the total query result which includes parent and child.

How can I get the latest X already transformed Parent rows?

Thanks.


回答1:


The way I would go here is:

  • load the list of root entity (Parent) and
  • let NHibernate load their children lazily - in separated SQL query.

To avoid 1 + N issue, we can use smart mapping feature:

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

So, the query should be like this:

session.QueryOver<Parent>()
    .Where(x => x.TimeStamp > from)
    .And(x => x.TimeStamp < to).OrderBy(x => x.TimeStamp).Desc
    //.Left.JoinQueryOver<Child>(x => x.Childs)
    // .TransformUsing(new DistinctRootEntityResultTransformer())
    .Skip(start) // paging
    .Take(maxCapacity)
    .List<Parent>();

And the parent mapping should be like:

<class name="Parent">
    ...
    <bag name="Childs" batch-size="3">
        ...
    </bag>
</class>

Please, check also these:

  • How to Eager Load Associations without duplication in NHibernate?
  • NHibernate QueryOver with Fetch resulting multiple sql queries and db hits
  • Is this the right way to eager load child collections in NHibernate


来源:https://stackoverflow.com/questions/27692331/nhibernate-select-one-to-many-left-join-take-x-latest-from-parent

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!