通过集合获取Paginated实体
考虑两个实体具有one-to-many
收集Vehicles
public class Person { public IList Vehicles { get; set;} } public class Vehicle { public string Name { get; set;} public Person Owner { get; set; } }
我显示一个有车辆的人员网格,并显示网格中第一辆车的名称。 网格是分页的。 我使用以下标准来获取数据
我有一个加载网格视图数据的标准
var criteria = DetachedCriteria.For() .CreateAlias("Vehicles","vehicle", JoinType.InnerJoin) .SetResultTransformer(new DistinctRootEntityResultTransformer()) .SetMaxResults(pageSize) .SetFirstResult((page - 1) * pageSize) criteria.Add(Restrictions.Eq("vehicle.Name", "super"));
其中page
和pageSize
是计算位。
问题是因为最大结果和第一个结果是在数据库中计算的,并且不同的根在外部完成,行数不匹配。
有没有办法解决这个问题?
这种查询应始终使用subquery
而不是任何类型的JOIN 。 这也意味着,colleciton项目引用了父项(如我们的情况) 。
所以,在这里我们为Vehicle
创建内部选择:
var vehicles = DetachedCriteria.For(); // 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"));
现在,我们可以调整上面的查询,只在root / parent级别上工作:
var criteria = DetachedCriteria.For() // 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)
那会像这样创建SELECT:
SELECT p.... FROM Person AS p WHERE p.ID IN ( SELECT v.OwnerId FROM Vehcile AS v WHERE v.Name = 'super' ... )
也可以看看:
- 查询HasMany引用
- 在NHibernate中,使用Disjunction可以得到双重结果
以及如何获取Vehicles
的集合(直到现在只用于过滤) ? 最好的(如果不是唯一的)方法是使用1 + 1 SELECT语句。 简单的内置解决方案是batch-size
设置。 只需使用此设置标记Vehicles
集合(例如batch-size="25"
),并使用更多SELECT语句,所有数据都将被有效加载。 看到:
- 19.1.5。 使用批量提取
- 如何在NHibernate中没有重复地加载加载关联?