Fetching Paginated Entity with Collection

前端 未结 1 488
慢半拍i
慢半拍i 2020-12-21 22:18

Consider two entities Person which has a one-to-many collection Vehicles

public class Person
{
    public IList

        
相关标签:
1条回答
  • 2020-12-21 22:43

    This kind of queries should always use subquery instead of any type of JOIN. That also means, that the colleciton item has reference to parent (as in our case).

    So, here we create the inner select for Vehicle:

    var vehicles = DetachedCriteria.For<Vehicle>();
    // add any amount or kind of WHERE parts
    vehicles.Add(Restrictions.Eq("vehicle.Name", "super"))
    // and essential SELECT Person ID
    vehicles.SetProjection( Projections.Property("Owner.ID"));
    

    Now, we can adjust the above query, to work only on a root/parent level:

    var criteria = DetachedCriteria.For<Person>()
    
    // instead of this
    // .CreateAlias("Vehicles","vehicle", JoinType.InnerJoin)
    
    // we will use subquery
    .Add(Subqueries.PropertyIn("ID", vehicles));
    
    // Wrong to use this approach at all
    //.SetResultTransformer(new DistinctRootEntityResultTransformer())
    
    .SetMaxResults(pageSize)
    .SetFirstResult((page - 1) * pageSize)
    

    That will create SELECT like this:

    SELECT p....
    FROM Person AS p
    WHERE p.ID IN (
      SELECT v.OwnerId
      FROM Vehcile AS v
        WHERE v.Name = 'super' ...
    )
    

    See also:

    • Query on HasMany reference
    • In NHibernate, using a Disjunction gives double results

    And how to fetch the collection of Vehicles (until now just used for filtering)? The best (if not only) way is to use 1+1 SELECT statements. The easy and built-in solution is batch-size setting. Just mark the collection of Vehicles with this setting (e.g. batch-size="25") and with few more SELECT statements all data will be effectively loaded. See:

    • 19.1.5. Using batch fetching
    • How to Eager Load Associations without duplication in NHibernate?
    0 讨论(0)
提交回复
热议问题