C# 使用nHibernate QueryOver连接子集

C# 使用nHibernate QueryOver连接子集,c#,sql,nhibernate,fluent-nhibernate,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 tblMem

我正在使用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,没有很多(任何)文档

我在其他地方看到了一些信息,但没有一个信息是非常清楚的,也没有一个关于为什么事情会以某种方式进行的实际解释。的答案没有给出一个足够的例子来说明它在做什么,所以我无法复制它

我已经获得了使用以下内容创建的查询的内部部分:

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[]>();

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

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

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

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查询优化器足够聪明,可以将其转换为内部联接。如果要确认这一点,可以使用SQLStudio生成并比较两个查询的执行计划

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();
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
)