【问题标题】:Nested Selects in Nhibernate QueryOverNhibernate QueryOver 中的嵌套选择
【发布时间】:2012-08-23 09:42:53
【问题描述】:

经过搜索,我没有发现任何真正有用的东西可以帮助我确定下一步的工作。

到目前为止,我只编写了相当简单的 nHibernate 查询,并有一个相对复杂的 SQL 查询,我需要在 QueryOver (Icriteria) 中抽出,或者如果证明过于繁琐,则使用 HQL。请在下面找到查询:

Select aliasTable1.Id, AliasTable1.Time, 
       AlaisTable2.Version,
       (select top 1 secondAliasTable1.Time
          from Table1 secondAliasTable1
          where aliasTable1.Time < secondAliasTable1.Time
            AND secondAliasTable1.Time < (SELECT Top 1 thirdAliasTable1.Time from Table1 thirdAliasTable1 
                                            where thirdAliasTable1.Name = 'stringValue1'
                                              AND thirdAliasTable1.Id = aliasTable1.Id
                                              AND thirdAliasTable1.Time > aliasTable1.Time
                                            ORDER By thirdAliasTable1.Time)
            AND secondAliasTable1.Name = 'stringValue2'
            AND secondAliasTable1.Id = aliasTable1.Id
            ORDER BY secondAliasTable1.Time) As 'Endtime'
  from Table1 aliasTable1
    INNER JOIN Table2 aliasTable2 on AliasTable2.Id = aliasTable1.table2Id
  where alaisTable1.Name = 'stringValue2'
  ORDER BY alaisTable1.Time

我在转换过程中遇到了这个查询真的碰壁了,所以我希望至少能找到一个让我继续前进的起点,如果不是完整的答案!

干杯

【问题讨论】:

  • @henrique 感谢您的代码编辑。出于某种原因,当我试图将其放入代码块时,我无法让它获取除了查询的第一行之外的任何内容。
  • 我通常只是选择整个代码,然后单击代码示例按钮。

标签: sql nhibernate hql queryover


【解决方案1】:

这将稍微取决于您的映射,但这样的事情应该可以工作:

Table1 aliasTable1 = null, secondAliasTable1 = null, thirdAliasTable1 = null;
Table2 aliasTable2 = null;

var result = session.QueryOver<Table1>(() => aliasTable1)
    .Where(p => p.Name == "stringValue1")
    .JoinQueryOver(p => p.Table2, () => aliasTable2)
    .SelectList(list => list
        .Select(() => aliasTable1.Id)
        .Select(() => aliasTable1.Time)
        .Select(() => aliasTable2.Version)
        .SelectSubQuery(
            QueryOver.Of<Table1>(() => secondAliasTable1)
                .Where(() => aliasTable1.Time < secondAliasTable1.Time)
                .WithSubquery.Where(() => secondAliasTable1.Time <
                    QueryOver.Of<Table1>(() => thirdAliasTable1)
                        .Where(() => thirdAliasTable1.Name == "stringValue1")
                        .And(() => thirdAliasTable1.Id == aliasTable1.Id)
                        .And(() => thirdAliasTable1.Time > aliasTable1.Time)
                        .SelectList(inner => inner
                            .Select(() => thirdAliasTable1.Time))                            
                        .OrderBy(() => thirdAliasTable1.Time).Asc()
                        .Take(1)
                        .As<DateTime>())
                .And(() => secondAliasTable1.Name == "stringValue2")
                .And(() => secondAliasTable1.Id == aliasTable1.Id)
                .SelectList(third => third
                    .Select(() => secondAliasTable1.Time))
                .OrderBy(() => secondAliasTable1.Time).Asc()
                .Take(1)))
    .OrderBy(() => aliasTable1.Time).Asc()
    .List<object[]>();

这会生成如下所示的 SQL:

SELECT this_.Id                            as y0_,
       this_.Time                          as y1_,
       aliastable1_.Version                as y2_,
       (SELECT TOP (1 /* @p0 */) this_0_.Time as y0_
        FROM   [Table1] this_0_
        WHERE  this_.Time < this_0_.Time
               and this_0_.Time < (SELECT TOP (1 /* @p1 */) this_0_0_.Time as y0_
                                             FROM   [Table1] this_0_0_
                                             WHERE  this_0_0_.Name = 'stringValue1' /* @p2 */
                                                    and this_0_0_.Id = this_.Id
                                                    and this_0_0_.Time > this_.Time
                                             ORDER  BY this_0_0_.Time asc)
               and this_0_.Name = 'stringValue2' /* @p3 */
               and this_0_.Id = this_.Id
        ORDER  BY this_0_.Time asc) as y3_
FROM   [Table1] this_
       inner join [Table2] aliastable1_
         on this_.Id = aliastable1_.Table1Id
WHERE  this_.Name = 'stringValue1' /* @p4 */
ORDER  BY this_.Time asc

除了.List&lt;object[]&gt;(),您还可以投影到您选择的DTO(使用TransformUsing)。如果这看起来势不可挡,我强烈建议将每个分离的 QueryOver 分解为它自己的变量,然后从主查询中引用它们。

更新:如果你想使用.TransformUsing,你需要创建一个null结果对象并使用.WithAlias()

Table1 aliasTable1 = null, secondAliasTable1 = null, thirdAliasTable1 = null;
Table2 aliasTable2 = null;
MyDTO dto = null;

var result = session.QueryOver<Table1>(() => aliasTable1)
    .Where(p => p.Name == "stringValue1")
    .JoinQueryOver(p => p.Table2, () => aliasTable2)
    .SelectList(list => list
        .Select(() => aliasTable1.Id).WithAlias(() => dto.Id)
        .Select(() => aliasTable1.Time).WithAlias(() => dto.Time)
        .Select(() => aliasTable2.Version).WithAlias(() => dto.Version)
        .SelectSubQuery(
            QueryOver.Of<Table1>(() => secondAliasTable1)
                .Where(() => aliasTable1.Time < secondAliasTable1.Time)
                .WithSubquery.Where(() => secondAliasTable1.Time <
                    QueryOver.Of<Table1>(() => thirdAliasTable1)
                        .Where(() => thirdAliasTable1.Name == "stringValue1")
                        .And(() => thirdAliasTable1.Id == aliasTable1.Id)
                        .And(() => thirdAliasTable1.Time > aliasTable1.Time)
                        .SelectList(inner => inner
                            .Select(() => thirdAliasTable1.Time))                            
                        .OrderBy(() => thirdAliasTable1.Time).Asc()
                        .Take(1)
                        .As<DateTime>())
                .And(() => secondAliasTable1.Name == "stringValue2")
                .And(() => secondAliasTable1.Id == aliasTable1.Id)
                .SelectList(third => third
                    .Select(() => secondAliasTable1.Time))
                .OrderBy(() => secondAliasTable1.Time).Asc()
                .Take(1)).WithAlias(() => dto.Time2))
    .OrderBy(() => aliasTable1.Time).Asc()
    .TransformUsing(Transformers.AliasToBean<MyDTO>())
    .List<MyDTO>();

【讨论】:

  • 我已经设置了要投影到的 DTO,并使用 CreateSQLQuery 让它工作。我会试试你提供的这个,然后回复你。
  • @DavidWatts:好的,如果您有任何问题,请告诉我。
  • 出于某种原因,我试图拉出的第四列总是被抛出为空。我想按 Id、开始时间、版本、结束时间的顺序返回这些列。结束时间是从与开始时间相同的表中提取的,但来自按名称引用的不同字段。我相信你从我的问题中理解了这一点,但它总是被返回为空。有什么想法吗?
  • 我不知道你有没有看到这个,因为我不知道它是否正确地引用了你
  • 哦,还有一件事......当我返回一个对象数组列表时,我得到的结果正常,但是在查询末尾使用这个 .TransformUsing(Transformers.AliasToBean&lt;TimeComparisonObject&gt;()).List&lt;TimeComparisonObject&gt;(); 会设置其中的所有项目对象为空。
【解决方案2】:

使用 HQL,假设您已经将实体映射到表:

可以通过这种方式显式完成连接:

Select aliasTable1.Id, aliasTable2.Version
  from Table1 as aliasTable1
    JOIN aliasTable1.table2 as aliasTable2;

另外,我不确定您是否可以在 HQL 的内部查询中设置 Top,因此您可以将其更改为:

AND secondAliasTable1.Time < (SELECT max(thirdAliasTable1.Time) from Table1 as thirdAliasTable1 
                                where thirdAliasTable1.Name = 'stringValue1'
                                  AND thirdAliasTable1.Id = aliasTable1.Id
                                  AND thirdAliasTable1.Time > aliasTable1.Time)

此外,如果您希望查询返回仅包含这 4 个属性(id、时间、版本和结束时间)的 DTO 列表,您应该查看 Transformers.aliasToBean()。

我曾经在这里写过一些东西:http://hordine.com/?p=1187

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多