名为Call的示例(简化)实体如下所示:
public virtual long Id { get; set; } public virtual string OriginatorNumber { get; set; } public virtual string DestinationNumber { get; set; } public virtual DateDimension DateDimension { get; set; }
实际模型的一些属性已被删除,因为它们无关紧要.简化的DateDimension如下所示:
public virtual long Id { get; set; } public virtual DateTime Date { get; set; } public virtual int DayOfMonth { get; set; } public virtual int Weekday { get; set; }
还有很多这样的专栏 – 它们通过应用程序设置预先填充了当前十年.因此,整个十年中的每个日期在此表中都有一行,每个调用都有一个指向它发生日期的链接.这全部映射在Fluent NHibernate并且工作正常.
如果我想做一些报告,我可以使用3.0中改进的NHibernate LINQ提供程序轻松完成.我们希望使用LINQ来提高我们的可维护性,但如果我们真的必须,我们将考虑HQL,ICriteria甚至纯sql.
所以说我想建立一个报告,显示来自某个数字的呼叫数量除以它们发生的星期几.我可以这样轻松地做到这一点:
var query = Calls .Where(c => c.OriginatorNumber == "402") .GroupBy(c => c.DateDimension.Weekday) .Select(g => new { Day = g.Key,Calls = g.Count() } );
在此示例中,“Calls”基本上是通过存储库接口从NHibernates LINQ提供程序(Query)返回的IQueryable.上面的查询给出了正确的结果,NHibernate Profiler向我展示了sql非常优秀,一切都很好.
但是,如果我想做一些更高级的事情,我会陷入困境.假设我想要每个工作日的平均呼叫次数.离上面不太远吧?我只需要弄清楚每个工作日在结果集中的唯一日期数,除以它的总呼叫次数,我们都设置好了 – 对吗?嗯,不,这是我开始遇到NHibernate LINQ提供程序的限制的地方.使用LINQ to对象,我可以构造一个查询来做到这一点 – 就像一些东西
.Select(g => g.Count() / g.GroupBy(c => c.DateDimension.Date).Count());
但是,在NHibernate中使用它时,这不会转换为正确的查询.相反,它将上面的.Count()调用转换为相同的调用记录数(*),因此结果始终为1.
我当然可以只查询每个调用,工作日和日期作为新的匿名对象,然后在应用程序方面进行数学计算,但根据传统观点,那就是错误(tm).我最终可能会绝望地做到这一点,甚至,当桌子增长到一百万个电话时,这意味着痛苦.
下面是一个SQL查询,它给出了我正在寻找的结果.
select ss.Weekday,AVG(cast(ss.Count as decimal)) from ( select dd.Weekday,dd.Date,COUNT(*) as Count from Call c left outer join DateDimension dd on c.DateDimension_id = dd.Id where c.OriginatorNumber = '402' group by dd.Weekday,dd.Date ) ss group by ss.Weekday order by ss.Weekday
是否可以使用NHibernate LINQ提供程序执行此操作?或者,如果那是不可能的,在我必须让应用程序获取中间结果并完成剩下的工作之前,我能有多接近?