如何为NHibernate中的关联指定排序条件?

如何为NHibernate中的关联指定排序条件?,nhibernate,Nhibernate,对于具有类型为ChildEntity的集合的实体ParentEntity,该集合包含类型为int的Order属性,如何通过使用NHibernate文档第12.4节中讨论的标准API检索父实体和按顺序排序的子集合 我尝试过使用类似以下的代码: public ParentEntity GetById(int id) { ICriteria criteria = _sessionFactory.GetCurrentSession().CreateCriteria(typeof (ParentE

对于具有类型为
ChildEntity
的集合的实体
ParentEntity
,该集合包含类型为int的
Order
属性,如何通过使用NHibernate文档第12.4节中讨论的标准API检索父实体和按顺序排序的子集合

我尝试过使用类似以下的代码:

public ParentEntity GetById(int id)
{
    ICriteria criteria = _sessionFactory.GetCurrentSession().CreateCriteria(typeof (ParentEntity));
    criteria.Add(Restrictions.Eq("Id", id))
        .CreateCriteria("Children")
        .AddOrder(Order.Desc("Order"));            
    return (ParentEntity) criteria.List()[0];
}
不幸的是,此代码生成2条
SELECT
语句。第一个select包含一个排序依据,它对检索到的关联列进行排序,但第二个select不包含排序依据,这似乎就是从中填充集合的列

注意,我已经尝试将NHibernate配置为执行外部联接获取,如果没有外部联接获取,则在没有条件的情况下可以正常工作。也就是说,它生成两个没有配置外部联接的查询,但只生成一个配置了外部联接的查询。添加的条件似乎会导致额外的查询

请限制回答如何使用criteria API完成这项工作,或者解释为什么这项工作不起作用。我知道排序可以通过映射来完成,但我试图理解使用criteria方法的具体问题

==编辑==== 以下是模型和映射:

public class ParentEntity
{
    public virtual int Id { get; private set; }
    public virtual IList<ChildEntity> Children { get; set; }

    public ParentEntity()
    {
        Children = new List<ChildEntity>();
    }
}

public class ChildEntity
{
    public virtual int Id { get; private set; }
    public virtual ParentEntity Parent { get; private set; }
    public virtual int Order { get; private set; }

    protected ChildEntity()
    {
    }

    public ChildEntity(int order)
    {
        Order = order;
    }
}

public class ParentEntityMap : ClassMap<ParentEntity>
{

    public ParentEntityMap()
    {
        WithTable("Parent");
        Id(p => p.Id);
        HasMany(p => p.Children)
            .KeyColumnNames.Add("Parent_Id")
            .Cascade.All();
    }
}

public class ChildEntityMap : ClassMap<ChildEntity>
{

    public ChildEntityMap()
    {
        WithTable("Child");
        Id(c => c.Id);
        Map(c => c.Order, "[Order]");
        References(c => c.Parent, "Parent_Id")
            .Cascade.All();
    }
}
公共类父实体
{
公共虚拟整数Id{get;private set;}
公共虚拟IList子项{get;set;}
公共父实体()
{
Children=新列表();
}
}
公共类子实体
{
公共虚拟整数Id{get;private set;}
公共虚拟父实体父{get;private set;}
公共虚拟整数顺序{get;私有集;}
受保护的子实体()
{
}
公共子实体(整数顺序)
{
订单=订单;
}
}
公共类ParentityMap:ClassMap
{
公共parentitymap()
{
WithTable(“母公司”);
Id(p=>p.Id);
有很多孩子(p=>p.Children)
.KeyColumnNames.Add(“父项Id”)
.Cascade.All();
}
}
公共类ChildEntityMap:ClassMap
{
公共儿童地图()
{
WithTable(“儿童”);
Id(c=>c.Id);
映射(c=>c.顺序,“[顺序]”);
参考资料(c=>c.父项,“父项Id”)
.Cascade.All();
}
}
==编辑2====
作为更新,在将Not.LazyLoad()添加到父级后,仅生成一个
SELECT
,但是,结果仍然未排序。

如何映射子级? 如果已将子项映射为“有序列表”(map/list/dictionary),则只能指示NHibernate应以有序方式检索子项

例如:

如果您已将这些子项映射为未排序的列表(集合/包),那么NHibernate将无法为您排序这些子项。在这种情况下,当用户访问这些子对象时,您必须对它们进行排序

public class Parent
{
    private ISet<Child> _children = new HashedSet<Child>();

    public ReadOnlyCollection<Child> Children
    {
        new List<Child>(_children).OrderBy(child => child.SequenceNr).ToList().AsReadOnly();
    }

}
公共类父类
{
私有ISet_children=new HashedSet();
公共只读集合子项
{
新列表(_children).OrderBy(child=>child.SequenceNr.ToList().AsReadOnly();
}
}

如果看不到您的模型和映射,会有点困难。但也许是这样的

 var criteria = session.CreateCriteria<ParentEntity>();
 criteria.Add(Restrictions.Eq("Id", id))
                .CreateAlias("Children", "children")
                .AddOrder(Order.Desc("children.Order"));
var-criteria=session.CreateCriteria();
标准。添加(限制。等式(“Id”,Id))
.CreateAlias(“儿童”、“儿童”)
.AddOrder(Order.Desc(“children.Order”);

从我观察到的行为来看,问题似乎是,虽然可以对关联设置约束(如第12.4节所示),但此类约束仅在其作为根实体的有意义过滤器的程度上相关。从DOCS中考虑下面的例子:

IList cats = sess.CreateCriteria(typeof(Cat))
.Add( Expression.Like("Name", "F%")
.CreateCriteria("Kittens")
    .Add( Expression.Like("Name", "F%") )
.List();
这意味着把所有名字以“F”开头的猫都还给我,但只给那些有名字以“F”开头的小猫的猫这并不是说返回名称以“F”开头的小猫。。订购的工作方式与此类似。我们可能会要求按名称订购小猫,NHibernate很乐意将其作为标准的一部分,但这种订购方式不会影响小猫的退货方式。因此,我的结论是,不能使用CriteriaAPI来过滤或排序返回的关联


上述文档部分确实指出,返回的关联未按标准进行预筛选,但在我理解关联标准的用途之前,我并不完全理解其含义。

我使用的是fluent,将集合声明为IList,并尝试将其映射为默认包和列表(例如,HasMany(x=>x.Children).AsList()),但两者都显示相同的结果。此外,生成的第一个SELECT对结果进行了正确排序,因此,如果没有生成第二个SELECT,则列表将按需要填充。我也尝试使用别名,但没有任何区别。