Статистический запрос в SQL - возможно ли это с NHibernate LINQ?

У меня есть приложение, которое использует несколько принципов хранилища данных, таких как размерное моделирование, для создания отчетов в довольно простой базе данных.

Пример (упрощенный) объект с именем 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 и работает нормально.

Если я хочу сделать некоторые отчеты, я могу легко сделать это с помощью улучшенного поставщика NHibernate LINQ в версии 3.0. Мы хотели бы использовать 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» - это, по сути, IQueryable, возвращаемый провайдером NHibernates LINQ (Query) через интерфейс репозитория. Приведенный выше запрос дает мне правильные результаты, NHibernate Profiler показывает мне, что SQL довольно оптимален, все в порядке.

Однако, если я хочу сделать что-то более продвинутое, я застреваю. Скажем, мне нужно среднее количество звонков в будний день. Не так уж и далеко от вышесказанного, правда? Мне просто нужно вычислить количество уникальных дат каждого дня недели в наборе результатов, разделить на него общее количество звонков, и все готово - верно? Ну нет, здесь я начинаю сталкиваться с ограничениями провайдера NHibernate LINQ. С помощью LINQ to objects я мог бы создать запрос для этого - что-то вроде

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

. Однако это не преобразуется в правильный запрос при использовании в NHibernate. Скорее, он превращает оба вызова .Count () в приведенном выше примере на одно и то же количество (*) записей вызовов, поэтому результат всегда равен 1.

Я МОГ, конечно, просто запросить каждый вызов, день недели и дату как новые анонимный объект, затем выполните вычисления на стороне приложения, но согласно общепринятому мнению, это просто неправильно (тм). Я мог закончить тем, что делал это в отчаянии, хотя, когда таблица вырастает до миллиона ++ вызовов, это причиняет боль.

Ниже приведен 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? Или, если это невозможно, как близко я могу подойти до того, как мне придется позволить приложению получить промежуточный результат и сделать все остальное?

8
задан Rune Jacobsen 8 February 2011 в 05:36
поделиться