【问题标题】:How do you specify a sort criteria for an association in NHibernate?如何在 NHibernate 中为关联指定排序标准?
【发布时间】:2010-01-06 00:10:12
【问题描述】:

对于具有ChildEntity类型集合的实体ParentEntity,其中包含一个int类型的Order属性,如何使用按Order排序的子集合检索父实体具体通过使用NHibernate 文档 here? 的第 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 语句。第一个选择包含一个order by,它对检索到的相关列进行排序,但第二个没有,这似乎是从中填充集合的那个。

注意,我已经尝试将 NHibernate 配置为进行外部连接提取,没有它可以在没有条件的情况下按预期工作。也就是说,它产生两个没有配置外连接的查询,但只产生一个配置了外连接的查询。无论如何,添加添加的条件似乎会导致额外的查询。

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

==== 编辑 ====

以下是模型和映射:

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,但是,结果仍然是未排序的。

【问题讨论】:

    标签: nhibernate


    【解决方案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 来过滤或排序返回的关联。

    文档的上述部分确实声明返回的关联没有被标准预先过滤,但在我了解关联标准的用途之前,我不太明白这是什么意思。

    【讨论】:

      【解决方案2】:

      你是如何绘制孩子们的地图的? 如果您已将它们映射为“有序列表”(映射/列表/字典),您只能指示 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();
          }
      
      }
      

      【讨论】:

      • 我正在使用 fluent,将集合声明为 IList,并尝试将映射作为默认包和列表(例如 HasMany(x => x.Children).AsList( )),但两者都显示相同的结果。
      • 此外,生成的第一个 SELECT 确实对结果进行了正确排序,因此如果没有生成第二个,那么似乎会根据需要填充列表。
      【解决方案3】:

      没有看到你的模型和映射有点难。但也许是这样的?

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

      【讨论】:

      • 我也尝试过使用别名,但没有任何作用。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-09-08
      • 1970-01-01
      • 1970-01-01
      • 2011-12-24
      • 2011-09-27
      • 2012-08-11
      相关资源
      最近更新 更多