查询HasMany引用
我有一个像这样的实体模型:
public class Request { public virtual IList Responses { get; set; } } public class Response { public virtual DateTime Timestamp { get; set; } public virtual bool Success { get; set; } }
我正在尝试创建一个Query ,它将向我提供所有请求 ,其中最新的响应 (关于其时间戳 )是成功的 。 如何才能做到这一点?
几乎总是如此,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() .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 (item => item.DateTime), Projections.Property(() => response.DateTime) )); // the middle SELECT var successSubquery = QueryOver.Of (() => response) // to filter the Request .Select(res => res.RequestId) .WithSubquery .WhereExists(maxSubquery) // now only these wich are successful .Where(success => success.Success == true) ;
此时我们必须嵌套内部SUB SELECT。 让我们用它们:
// the most outer SELECT var query = session.QueryOver(); query.WithSubquery // our Request ID is IN(... .WhereProperty(r => r.ID) .In(successSubquery); var list = query .List ();
最后的笔记,我不是在讨论这个概念。 不是表现。 我会在响应“IsActive”上使用相当的设置并使其更容易 ……这只是答案如何做到这一点……
我会对此进行一次尝试,这里有一些linq(使用Query
代替)。
session.Query() .Where(request => request.Responses.Count() > 0 && request.Responses.OrderByDescending(response => response.Timestamp) .First() .Success);
不知道这是否有效。