Как почти всегда, у NHibernate есть ответ на этот вопрос. То, что мы здесь пытаемся достичь бы SQL заявление смотрит так:
// final Request selection
SELECT request.[RequestId]
FROM [Request] request
// Only requests, which are successful, and have Max(date)
WHERE request.[RequestId] IN
(
SELECT successResponse.RequestId as y0_
FROM [Response] successResponse
// response which max date is equal to the upper response
// and which RequestId corresponds with supper upper Request
WHERE EXISTS
(
SELECT maxResponse.RequestId as y0_
, max(maxResponse.[DateTime]) as y1_
FROM [Response] maxResponse
// do the MAX only for current Request
WHERE maxResponse.RequestId = successResponse.RequestId
GROUP BY maxResponse.RequestId
// assure that the Response match is on the max DateTime
HAVING max(maxResponse.[DateTime]) = successResponse.[DateTime]
)
AND successResponse.[Success] = 1
)
Примечание:
- Ожидая Ответдействительно есть
RequestId
- выше, использовал C#
//
комментарий вместо SQL --
И теперь магия NHibernate и QueryOver:
// This declaration will allow us, to use a reference from middle SELECT
// in the most deeper SELECT
Response response = null;
// the most INNER SELECT
var maxSubquery = QueryOver.Of<Response>()
.SelectList(l => l
.SelectGroup(item => item.RequestId)
.SelectMax(item => item.DateTime)
)
// WHERE Clause
.Where(item => item.RequestId == response.RequestId)
// HAVING Clause
.Where(Restrictions.EqProperty(
Projections.Max<Response>(item => item.DateTime),
Projections.Property(() => response.DateTime)
));
// the middle SELECT
var successSubquery = QueryOver.Of<Response>(() => response)
// to filter the Request
.Select(res => res.RequestId)
.WithSubquery
.WhereExists(maxSubquery)
// now only these wich are successful
.Where(success => success.Success == true)
;
На данный момент мы имеем к внутреннему Выбору подфункции, вложенный. давайте их использовать:
// the most outer SELECT
var query = session.QueryOver<Request>();
query.WithSubquery
// our Request ID is IN(...
.WhereProperty(r => r.ID)
.In(successSubquery);
var list = query
.List<Request>();
Заключительные замечания, я не обсуждаю концепцию. Не производительность. Я бы использовал скорее настройку ответа «IsActive» и упростил ее ... это как раз ответ, как это сделать ...
Спасибо за ваш ответ. Что делать, если я не могу ожидать, что мои ответы * всегда будут иметь * RequestId *? – dhrm
Честно говоря, я вижу это так: вы добавили некоторую * бизнес-логику *, которая сможет пометить последнюю запись как «IsActive» (новый столбец). Если вы не пойдете этим путем ... тогда вы не сможете этого SQL-оператора без столбца «RequestId» - точно. Итак, если этот столбец существует ... он ** должен быть отображен в вашем объекте Reponse ** ... как отношение. Тогда вы можете использовать мой способ ... никакой другой вариант, я бы сказал;) удачи в NHibernate –
Radim, можете ли вы объяснить, что здесь делает ** SelectList **? Кроме того, будет ли он работать так же, как и заказывать ответы в ** maxSubquery ** по дате начала, а затем Take (1)? – Michael