【问题标题】:using nHibernate QueryOver to join a subset使用 nHibernate QueryOver 加入子集
【发布时间】:2014-09-16 23:32:26
【问题描述】:

我正在使用 nHibernate 进行数据库访问。我需要做一个复杂的查询来查找特定日期之后的所有成员日记帐分录,并为每个成员设置了特定值 PreviousId。我可以轻松地为它编写 SQL:

SELECT J.MemberId, J.PreviousId
FROM tblMemMemberStatusJournal J 
INNER JOIN (
    SELECT MemberId,
        MIN(EffectiveDate) AS EffectiveDate
    FROM tblMemMemberStatusJournal 
    WHERE EffectiveDate > @StartOfMonth
        AND (PreviousId is NOT null)
    GROUP BY MemberId
) AS X ON (X.EffectiveDate = J.EffectiveDate AND X.MemberId = J.MemberId)

但是,我在尝试让 nHibernate 生成此信息时遇到了很多麻烦。关于如何使用 QueryOver 的文档并不多(任何)。

我一直在其他地方看到信息,但都不是很清楚,也很少有关于为什么以某些方式完成事情的实际解释。 Selecting on Sub Queries in NHibernate with Critieria API 的答案没有给出一个充分的例子来说明它在做什么,所以我无法复制它。

我已经得到了用这个创建的查询的内部部分:

IList<object[]> result = session.QueryOver<MemberStatusJournal>()
        .SelectList(list => list
            .SelectGroup(a => a.Member.ID)
            .SelectMin(a => a.EffectiveDate))
        .Where(j => (j.EffectiveDate > firstOfMonth) && (j.PreviousId != null))
        .List<object[]>();

根据分析器的说法,这会产生以下 SQL:

SELECT this_.MemberId           as y0_,
   min(this_.EffectiveDate) as y1_
FROM   tblMemMemberStatusJournal this_
WHERE  (this_.EffectiveDate > '2014-08-01T00:00:00' /* @p0 */
    and not (this_.PreviousLocalId is null))
GROUP  BY this_.MemberId

但我没有找到一个很好的例子来说明如何将这个子集与父查询实际连接起来。有人有什么建议吗?

【问题讨论】:

    标签: c# sql nhibernate fluent-nhibernate


    【解决方案1】:

    您实际上并没有加入一个子集,而是在一个子集上进行过滤。了解这一点后,您可以选择通过其他方式进行过滤,在本例中为相关子查询。

    下面的解决方案首先创建一个分离的查询作为内部子查询。我们可以通过使用别名将内部查询的属性与外部查询的属性关联起来。

    MemberStatusJournal memberStatusJournalAlias = null; // This will represent the 
                                                         // object of the outer query
    
    var subQuery = QueryOver.Of<MemberStatusJournal>()
                      .Select(Projections.GroupProperty(Projections.Property<MemberStatusJournal>(m => m.Member.ID)))
                      .Where(j => (j.EffectiveDate > firstOfMonth) && (j.PreviousId != null))
                      .Where(Restrictions.EqProperty(
                                 Projections.Min<MemberStatusJournal>(j => j.EffectiveDate),
                                 Projections.Property(() => memberStatusJournalAlias.EffectiveDate)
                             )
                            )
                      .Where(Restrictions.EqProperty(
                                Projections.GroupProperty(Projections.Property<MemberStatusJournal>(m => m.Member.Id)),
                                Projections.Property(() => memberStatusJournalAlias.Member.Id)
                           ));
    
    var results = session.QueryOver<MemberStatusJournal>(() => memberStatusJournalAlias)
                         .WithSubquery
                         .WhereExists(subQuery)
                         .List();
    

    这将产生如下 SQL 查询:

    SELECT blah
    FROM tblMemMemberStatusJournal J 
    WHERE EXISTS (
        SELECT J2.MemberId
         FROM tblMemberStatusJournal J2
        WHERE J2.EffectiveDate > @StartOfMonth
            AND (J2.PreviousId is NOT null)
        GROUP BY J2.MemberId
        HAVING MIN(J2.EffectiveDate) = J.EffectiveDate
        AND J2.MemberId = J.MemberId
    )
    

    这看起来比您打开问题时使用的 inner join 查询效率低。但我的经验是 SQL 查询优化器足够聪明,可以将其转换为内部连接。如果要确认这一点,可以使用 SQL Studio 生成并比较两个查询的执行计划。

    【讨论】:

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