Статистический запрос в SQL - возможно ли это с помощью NHibernate LINQ? - PullRequest
8 голосов
/ 08 февраля 2011

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

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

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

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

1 Ответ

1 голос
/ 11 февраля 2011

Есть много вещей, которые вы не можете сделать с поставщиком LINQ.Использование HQL или CreateCriteria - это то, что вы должны будете принять с помощью NHibernate.

Я не пробовал, но, похоже, вы сможете делать то, что хотите, используя HQL или CreateCriteria (сDetatchedCriteria).

Если вы в отчаянии, вы также можете использовать простой SQL с помощью CreateSqlQuery.

...