具有多列联接的Nhibernate子查询

本文关键字:Nhibernate 查询 | 更新日期: 2023-09-27 18:19:40

我有计划和计划版本的数据库结构,关系如下:

 +------+                  +-------------+
 | Plan |  --------------> | PlanVersion |
 +------+  1        (1..n) +-------------+

PlanVersion是跟踪所有版本更改的版本表,它有ActiveFromDataActiveToDataarrentPlanId列,告诉我们版本的当前子计划是什么。

我想要的是得到一段时间以来所有子计划和特定计划的所有更改。这个查询就是我附带的:

DECLARE @since datetime;
set @since = '2014-08-27 12:00:00.000';
DECLARE @parrentPlan bigint;
set @parrentPlan = 1;
SELECT pv.* 
FROM [dbo].[PlanVersion] pv
INNER JOIN
    /* Query Over subselect*/
    (
       SELECT PlanId, MAX(ActiveFromDate) AS MaxActiveFromDate
       FROM [dbo].[PlanVersion] pv 
       WHERE pv.ParentPlanId=@parrentPlan
       GROUP BY PlanId
    ) groupedVersions
ON pv.ParentPlanId = groupedVersions.PlanId 
    AND pv.ActiveFromDate = groupedVersions.MaxActiveFromDate
WHERE (pv.ActiveFromDate>=@since OR pv.ActiveToDate>@since) 

现在我想把它翻译成Nhibernate QueryOver:我有这个代码

var subquery = QueryOver.Of<PlanVersion>()
                    .Where(x => x.ParentPlan.Id == parrentPlanId)
                    .Select(
                         Projections.Group<PlanVersion>(e => e.ParrentPlan.Id),
                         Projections.Max<PlanVersion>(e => e.ActiveFromDate)
                    );

但我不知道如何在QueryOver中编写suquery的Two列的内部联接。

注:

  1. 我们在测试中使用了Nhibernate 3.3和4.0
  2. 这个查询将是轮询的一部分,所以性能对我来说非常重要

具有多列联接的Nhibernate子查询

我想说,这是有解决方案的。事实上,我们必须使用稍微复杂一点的SQL。我已经在这里深入解释了这种方法:

  • HasMany参考文献查询

所以,下面只是基于您的子查询草稿的草稿。事实上,我们正在做的是创建两个子选择(请在此处查看预期的SQL)

PlanVersion planVersion = null;
// the most INNER SELECT
var maxSubquery = QueryOver.Of<PlanVersion>()
   .SelectList(l => l
    .SelectGroup(item => item.ParentPlan.Id)
    .SelectMax(item => item.ActiveFromDate)
    )
    // WHERE Clause
   .Where(item => item.ParentPlan.Id == planVersion.ParentPlan.Id)
   // HAVING Clause
   .Where(Restrictions.EqProperty(
      Projections.Max<PlanVersion>(item => item.ActiveFromDate),
      Projections.Property(() => planVersion.ActiveFromDate)
    ));
// the middle SELECT
var successSubquery = QueryOver.Of<PlanVersion>(() => planVersion )
    // the Plan ID
    .Select(pv => pv.ParentPlan.Id)
    .WithSubquery
    .WhereExists(maxSubquery)
    ;

有了这些子查询,我们可以要求计划本身:

// the most outer SELECT
var query = session.QueryOver<Plan>()
    .WithSubquery
    .WhereProperty(p => p.Id)
    .In(successSubquery)
    .List<Plan>();

可能有一些小的打字错误,但草案应该给你明确的答案如何…