c# - 使用 nHibernate QueryOver 加入一个子集

标签 c# sql nhibernate fluent-nhibernate

我正在使用 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

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

最佳答案

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

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

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 生成并比较两个查询的执行计划。

关于c# - 使用 nHibernate QueryOver 加入一个子集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25879987/

相关文章:

c# - assembly 中的类型是使用旧版本的 blend sdk 构建的,在 Windows presentation Foundation 4 项目中不受支持

c# - 问题级联下拉列表,生成的下拉列表未将选定值发布到服务器

sql - 完全连接同一列上的多个表

sql - 我应该让 JPA 还是数据库级联删除?

mysql - 如何在NHibernate QueryOver中的Join语句中而不是在Where block 中指定多个条件

c# - 在 Entity Framework Core 中使用具有多对多关系的列表

C# 和 SQLite : Resource to Array

sql - 在 EXCEL 中构建 SQL SELECT 语句

nhibernate - 查询实体时如何强制 NHibernate 访问数据库?

nhibernate - 如何使用 Fluent NHibernate 设置自定义 DriverConnectionProvider