【问题标题】:NHibernate Projections (QueryOver.SelectList) limitsNHibernate Projections (QueryOver.SelectList) 限制
【发布时间】:2012-08-20 01:58:27
【问题描述】:

我是 stackoverflow 的新手,我希望这个问题会受到赞赏。

简单地说:我从表 x 左外连接表 y 中选择所有内容。表 x 的列太多,所以我创建了新对象 x。该对象用于投影。我可以投影我想要的表 x 的每一列。但是当我尝试投影/选择一个集合(表 y 的集合)时,我得到了同样的错误:'索引超出了数组的范围'。

我的问题:NHibernate 是否支持选择/投影集合?因为我通过在谷歌(和 stackoverflow)上搜索多次看到这个问题,但这些问题都没有得到回答。

代码示例:

public class X
{
    public virtual int ID { get; set; }
    public virtual int IDontNeedMoreInfoAboutClassXItTakesToMuchTimeToRetrieve { get; set; }
    public virtual IList<Y> YCollection { get; set; }
}

public class Y
{
    public virtual int YID { get; set; }
}

public class XRepository{
    public ISession Session {get; set;}
    public IList<X> Get()
    {

        X xAlias = null;
        Y yAlias = null;
        X resultAlias = null;
        return Session.QueryOver<X>()
            .JoinAlias(() => xAlias.YCollection, () => yAlias, JoinType.LeftOuterJoin)
            .SelectList(list => list
                .SelectGroup(() => xAlias.ID).WithAlias(() => resultAlias.ID)
                .SelectGroup(() => xAlias.YCollection).WithAlias(() => resultAlias.YCollection)) // Index was outside the bounds of the array
                .TransformUsing(Transformers.AliasToBean<X>()).List<X>();
    }
}

【问题讨论】:

  • X 是 DTO 还是映射类?
  • 好问题:X 是一个映射类。我知道我也使用映射类作为结果(resultAlias),但是如果我使用 dto 或映射类作为返回对象,它并没有太大的区别。它只是关于忽略 sql 的 select 语句中的某些列。
  • 我认为您不必自己加入。如果Y 集合被正确映射,那么您所要做的就是Session.QueryOver&lt;X&gt;().Fetch(x =&gt; x.YCollection).Eager。 nHib 将为您生成左外连接。 X 的任何你不想要的属性都可以设置为 Fetch().Lazy
  • 这可能是解决我的问题的好方法。不幸的是,大多数时候我确实需要对象 x 的每个属性。它仅适用于 1 个函数,我只需要对象 x 的几个属性。对象 x 有大约 30 列。大多数列将在其他地方使用。现在我有一个函数必须获取大约 10.000 条记录。这个功能很慢。在 mssql 上测试只需要我只使用几列的 1/4 时间。上面的代码是明确选择我需要的项目的一个很好的例子。只有集合似乎仍然不起作用(顺便说一句,dto 也是一个选项)。

标签: nhibernate c#-4.0 projection queryover selectlist


【解决方案1】:

返回的结果必须与完整的内容进行分组(因此 sql 不可用,因为它只能对分组的项目进行聚合)但 NHibernate 只能对 m,apped 实体执行此操作,因为它知道分组依据的身份。手动操作很简单

Y yAlias = null;
var tempResults = Session.QueryOver<X>()
     .JoinAlias(x => x.YCollection, () => yAlias, JoinType.LeftOuterJoin)
     .SelectList(list => list
         .Select(() => xAlias.Id)
         .Select(() => xAlias.Name)
         ...
         .Select(() => yAlias.Id)
         ...
     .ToList<object[]>()

List<X> results = new List<X>(100); // switch to Hashset if too slow and order does not matter
foreach(var row in tempResults)
{
    Y y = new Y { Id = (long)row[4], ... };
    X x = results.FirstOrDefault(x => x.Id == (long)row[0]));
    if (x != null)
        x.YCollection.Add(y);
    else
        results.Add(new X { Id = (long)row[0], ..., YCollection = { y } };
}

return results;

【讨论】:

  • 如果我理解正确:我必须在“tmpResults”中检索扁平化结果,然后我必须重新创建正确的对象。我想我理解为什么应该以这种方式实施。谢谢,我尽快试试这个解决方案!
  • 感谢您的解决方案。我使用的最大区别是使用临时(扁平)dto 来存储数据而不是 object[]。现在我可以在运行时防止错误更好的装箱性能。
猜你喜欢
  • 2010-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多