问题
I have database structure for Plans and PlanVersions in following relationship:
+------+ +-------------+
| Plan | --------------> | PlanVersion |
+------+ 1 (1..n) +-------------+
PlanVersion is version table tracking all version changes and it have ActiveFromData and ActiveToData columns show us when was this version active. Plan also can have SubPlans which can change in time so PlanVersion also have ParrentPlanId column which tell us what was current subplan for version.
What i want is to get all changes of all SubPlans since some time and for specific Plan. This query is what i came with:
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)
Now i want is translate that to Nhibernate QueryOver: i have this code
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)
);
But i dont know how to write that inner join on Two columns from suquery in QueryOver.
Notes:
- We use Nhibernate 3.3 with 4.0 in testing
- This query will be part of polling so performance is really important for me
回答1:
I would say, that this has solution. We have to use a bit more complex SQL in fact. This approach I've already deeply explained here:
- Query on HasMany reference
So, below is just a draft based on your subquery draft. What we are doing, is creating two subselects in fact (check the intended SQL here)
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)
;
having this subqueries, we can ask for plan itself:
// the most outer SELECT
var query = session.QueryOver<Plan>()
.WithSubquery
.WhereProperty(p => p.Id)
.In(successSubquery)
.List<Plan>();
There could be some minor typos, but the draft should give you clear answer how to...
来源:https://stackoverflow.com/questions/25530018/nhibernate-subquery-with-multiple-columns-join