我正在使用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的文档并不多。
我曾经在其他地方看到过信息,但是这些信息都不是很清楚,也很少有关于为什么以某些方式完成事情的实际解释。使用Critieria API在NHibernate中选择子查询的答案并未给出有关其功能的充分示例,因此我无法复制它。
我已经获得了使用此命令创建的查询的内部:
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生成并比较两个查询的执行计划。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句