2011-02-07 67 views
8

我有一个应用程序,它使用一些数据仓库原理(如维度建模)在相当简单的数据库上进行报告。SQL中的统计查询 - 这可能与NHibernate的LINQ?

一个例子(简体)实体命名的呼叫看起来是这样的:

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; } 

有很多更喜欢这个栏目 - 他们预填充通过应用程序安装在当前十年。因此,整个十年中的每个日期在该表中都有一排,每个Call都有一个到它发生日期的链接。这是所有映射在流利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() }); 

在这个例子中,“呼叫”基本上是一个IQueryable通过仓库接口从NHibernates LINQ提供程序(查询)返回。上面的查询给了我正确的结果,NHibernate Profiler告诉我SQL是非常优化的,一切都很好。

但是,如果我想做些稍微更高级的事情,我会陷入困境。假设我希望每周工作日的平均通话次数。离上述不太远,对吧?我只需要计算出每个工作日在结果集中的唯一日期数量,然后除以它的总呼叫数量,然后我们全部设置 - 对吗?嗯,不,这是我开始碰到NHibernate LINQ提供商的限制。随着LINQ到对象我可以构造一个查询做到这一点 - 沿

.Select(g => g.Count()/g.GroupBy(c => c.DateDimension.Date).Count()); 

线的东西。然而,在NHibernate的使用时,这并不转换成正确的查询。相反,它将上面的两个.Count()调用转换为呼叫记录的相同计数(*),因此结果始终为1.

我当然可以查询每个呼叫,工作日和日期作为新的匿名对象,然后在应用程序方面进行数学运算,但根据传统的看法,这是错误的(t​​m)。我可能会在绝望中做到这一点,即使是这样,当表格增长到一百万次以上时,这也意味着痛苦。

下面是一个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提供程序执行此操作?或者,如果这是不可能的,那么我必须让应用程序获取中间结果并完成剩下的工作,然后再离开我有多近?

+0

也许你正在走错方向。如何创建星型模式并预先填充计算的度量? – epitka 2011-02-08 14:02:26

+0

好吧,这是一个有趣的观点 - 但是,我的理解是,“事实”表中的每个实体(即我的示例中的调用)对每个相关维度表都有一个FK。我如何创建一个星型模式,以帮助我找出呼叫的日期,并从每个呼叫记录中指出它?但是总的来说,我对这种错误的方式进行讨论的可能性非常开放。 :) – 2011-02-08 14:43:40

回答

1

有很多事情你不能用LINQ提供程序来做。使用HQL或CreateCriteria只是你必须接受NHibernate的一些东西。

我还没有尝试过,但看起来应该可以使用HQL或CreateCriteria(使用DetatchedCriteria)来执行您想要的操作。

如果您绝望,也可以使用CreateSqlQuery回退到纯SQL。