SQL 中的统计查询 - NHibernate LINQ 可以实现吗?

发布于 2024-10-16 02:13:36 字数 2189 浏览 2 评论 0原文

我有一个应用程序,它使用一些数据仓库原理(例如维度建模)来对相当简单的数据库进行报告。

名为 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 提供程序(查询)返回的 IQueryable。上面的查询给了我正确的结果,NHibernate Profiler 向我显示 SQL 非常优化,一切都很好。

然而,如果我想做一些更高级的事情,我就会陷入困境。假设我想要每个工作日的平均呼叫数。离上面的也不算太远吧?我只需要计算出结果集中每个工作日的唯一日期的数量,将调用总数除以它,我们就都准备好了 - 对吗?嗯,不,这就是我开始遇到 NHibernate LINQ 提供程序限制的地方。使用 LINQ to object,我可以构造一个查询来执行此操作 - 类似于

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

但是,在 NHibernate 中使用它时,这不会转换为正确的查询。相反,它将上面的两个 .Count() 调用转换为相同的调用记录 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 提供程序来做到这一点?或者,如果这是不可能的,那么在我必须让应用程序获取中间结果并执行其余操作之前,我能达到多接近的目标?

I have an application that uses a few data warehousing principles such as dimensional modeling to do reporting on a fairly simple database.

An example (simplified) entity named Call looks like this:

    public virtual long Id { get; set; }
    public virtual string OriginatorNumber { get; set; }
    public virtual string DestinationNumber { get; set; }
    public virtual DateDimension DateDimension { get; set; }

A few of the properties of the real model have been removed as they are irrelevant. The simplified DateDimension looks like this:

    public virtual long Id { get; set; }
    public virtual DateTime Date { get; set; }
    public virtual int DayOfMonth { get; set; }
    public virtual int Weekday { get; set; }

There are a LOT more columns like this - they are prepopulated for the current decade by application setup. So each date in the entire decade has a row in this table, and each Call has a link to the date that it occured. This is all mapped in Fluent NHibernate and working fine.

If I want to do some reporting, I can do this easily with the improved NHibernate LINQ provider in 3.0. We would like to use LINQ for the improved maintainability it gives us, but if we really MUST, we'll consider HQL, ICriteria or even plain SQL.

So say I want to build a report that shows the number of calls from a certain number, divided by the day of the week they occur. I can do that easily this way:

        var query = Calls
            .Where(c => c.OriginatorNumber == "402")
            .GroupBy(c => c.DateDimension.Weekday)
            .Select(g => new { Day = g.Key, Calls = g.Count() } );

In this example, "Calls" is basically an IQueryable returned from NHibernates LINQ provider (Query) through a repository interface. The query above gives me the correct results, NHibernate Profiler shows me that the SQL is pretty optimal, all is well.

However, if I want to do something slightly more advanced, I get stuck. Say I want the average number of calls per weekday. Not too far from the above, right? I just need to figure out the number of unique dates each weekday has in the result set, divide the total number of calls by it, and we're all set - right? Well, no, this is where I start to hit the limitations of the NHibernate LINQ provider. With LINQ to objects I could construct a query to do it - something along the lines of

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

However, this does not convert into the correct query when using it in NHibernate. Rather, it turns both .Count() calls in the above to the same count(*) of call records, so the result is always 1.

I COULD of course just query for each call, weekday and date as a new anonymous object, then do the math on the application side, but according to conventional wisdom, That's Just Wrong (tm). I could end up doing it in desperation, tho, even tho it means pain when the table grows to a million++ calls.

The below is an SQL query that gives me the result I am looking for.

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

Is it possible to do this with the NHibernate LINQ provider? Or, if that is not possible, how close can I get before I have to let the application fetch the intermediary result and do the rest?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小瓶盖 2024-10-23 02:13:36

有很多事情无法通过 LINQ 提供程序完成。对于 NHibernate,您必须接受使用 HQL 或 CreateCriteria。

我还没有尝试过,但看起来您应该能够使用 HQL 或 CreateCriteria (使用 DetatchedCriteria)做您想做的事情。

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

There are a lot of things you can't do with the LINQ provider. Using HQL or CreateCriteria is just something you'll have to accept with NHibernate.

I haven't tried it, but it looks like you should be able to do what you want to do using HQL or CreateCriteria (with DetatchedCriteria).

If you are desperate you can also fall back to plain SQL using CreateSqlQuery.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文