2010-01-06 21 views
2

对于实体ParentEntityChildEntity类型的集合,其包含int类型的Order属性,如何能父实体可以与子集特别是通过使用标准 API的由Order排序检索如在部分12.4中讨论NHibernate文档here如何为NHibernate中的关联指定排序条件?

我使用类似于下面的代码尝试:

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语句。第一个选择包含一个order by,它对检索到的关联列进行排序,但第二个不包含,并且这似乎是集合正在从其中填充的列。

请注意,我已经尝试配置NHibernate做一个外部联合提取没有它按预期工作没有条件。也就是说,它会在没有配置外部联接的情况下生成两个查询,但只有一个配置了外部联接。无论如何,添加的标准似乎都会导致额外的查询。

请限制回答如何使用标准API或解释说明为什么这不起作用。我知道排序可以通过映射完成,但我试图了解具体问题是使用标准方法。

==== EDIT ====

下面是该模型和映射:

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(); 
    } 
} 

====编辑2 ====

作为更新将Not.LazyLoad()添加到Parent后,仅生成一个SELECT,但结果仍未排序。

回答

1

从我观察的行为,这个问题似乎是同时约束可根据关联被放置(如图中docs的部分12.4),这样的约束仅只要相关的是它们作为根实体的有意义的过滤器。从文档请看下面的例子:

IList cats = sess.CreateCriteria(typeof(Cat)) 
.Add(Expression.Like("Name", "F%") 
.CreateCriteria("Kittens") 
    .Add(Expression.Like("Name", "F%")) 
.List(); 

这是说给我回其中名称以“F”开头的所有猫,但它只能有一个名称以“F”小猫那些猫。这并不是说小猫的姓名以“F”开头。订购以类似的方式工作。我们可能会问小猫是按名字排序的,NHibernate很乐意作为标准的一部分传递下去,但这样的排序与小猫的返回没有关系。因此,我的结论是使用Criteria API不能用于过滤或排序返回的关联。

上述的文档部分并没有说明返回的关联没有按照标准进行预先过滤,但我并不完全明白是什么意思,直到我理解了关联标准的用途。

0

你是怎么映射孩子的? 如果你已经将它们映射为'有序列表'(地图/列表/字典),那么你只能指出NHibernate应该以有序的方式检索这些子项。

例如: http://ayende.com/Blog/archive/2009/06/02/nhibernate-mapping-ltlistgt.aspx

我有你映射的儿童作为联合国有序列表(套/袋),那么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(); 
    } 

} 
+0

我正在使用流利,将集合声明为IList ,并尝试将映射作为默认包和列表(例如HasMany(x => x.Children).AsList()),但都显示相同的结果。 – 2010-01-06 15:19:31

+0

此外,生成的第一个SELECT会正确地对结果进行排序,所以看起来如果第二个SELECT没有被生成,那么该列表将根据需要填充。 – 2010-01-06 15:22:06

0

有点难以看到您的模型和映射。但也许这样?

var criteria = session.CreateCriteria<ParentEntity>(); 
criteria.Add(Restrictions.Eq("Id", id)) 
       .CreateAlias("Children", "children") 
       .AddOrder(Order.Desc("children.Order")); 
+0

我尝试使用别名,但它没有区别。 – 2010-01-07 12:47:04