2009-09-03 4 views
6

я в основном пытаются создать этот запрос с интерфейсом NHibernate ICriteria:NHibernate 2.1: LEFT JOIN на подзапрос с Алиас (ICriteria)

SomeTable 1: п AnotherTable

SomeTable имеет столбцы: PrimaryKey, NonAggregateColumn
AnotherTable имеет столбцы: PrimaryKey, ForeignKey, AnotherNonAggregate, YetAnotherNonAggregate

SELECT 
     table1.NonAggregateColumn, 
     subquery.SubQueryAggregate1, 
     subquery.SubQueryAggregate2 
FROM 
     SomeTable AS table1 
     LEFT JOIN 
     (
      SELECT 
       table2.ForeignKey, 
       COUNT(table2.AnotherNonAggregate) AS SubQueryAggregate1, 
       AVG(table2.YetAnotherNonAggregate) AS SubQueryAggregate2 
      FROM AnotherTable AS table2 
      GROUP BY (table2.ForeignKey) 
    ) AS subquery ON subquery.ForeignKey = table1.PrimaryKey 

Понятно, что использование подзапроса Projection не очень эффективно, поскольку SQL приходится дважды сканировать таблицу (один подзапрос проекции на совокупность).

Использование нескольких команд GROUP BY также неэффективно.

Есть ли решение для этого? До сих пор я прибегал к использованию raw SQL, но это становится громоздким для сложных отчетов.

+0

Уточнить вопрос? Запрос, который вы показываете, является родным sql. Он уже возвращает ожидаемые данные? Вы хотите превратить его в критерии. Почему бы не HQL? –

+0

Забыл упомянуть: вы используете ORM. Поэтому, чтобы написать запрос, вам не нужно слишком много заботиться о таблицах и внешнем ключе. Гораздо важнее сущности и определения отображения. Итак, как они отображаются на таблицах? Есть ли список в SomeTable? Есть ли ссылка в AnotherTable? Или оба? –

+0

Да, исходный запрос возвращает необходимые данные для отчета. Я использую NHibernate 2.1. Критерии API предпочтительнее из-за сильной типизирующей способности через NHLambdaExtensions (который я также использую). Я использую имена SomeTable, AnotherTable, чтобы сделать SQL ясным и легко читаемым. Это фиктивное зеркало реальных объектов. SomeTable сопоставленный объект имеет обратную коллекцию one-to-many объектов AnotherTable. –

ответ

2

К сожалению, критерии немного ограничены.

Попробуйте это:

session.CreateCriteria(typeof(SomeTable), "st") 
    .SetProjection(Projections.ProjectionList() 
    .Add(Projections.GroupProperty("st.id")) 
    .Add(Projections.GroupProperty("st.NonAggregateColumn")) 
    .Add(Projections.RowCount(), "rowcount") 
    .Add(Projections.Avg("at.YetAnotherNonAggregate"), "avg")); 
    .CreateCriteria("st.OtherTables", "at", JoinType.InnerJoin) 
    .List<object[]>(); 

Вы, вероятно, нужно играть вокруг немного, это скорее догадка. Это также может быть невозможно таким образом.

Она должна производить что-то вроде этого:

select 
    st.id, 
    st.NonAggregateColumn, 
    count() as "rowcount", 
    avg(at.YetAnotherNonAggregate) as "avg" 
from 
    SomeTable st inner join AnotherTable at on ... 
group by 
    st.id, 
    st.NonAggregateColumn 

Вообще:

  • Вы можете сделать подзапросы с помощью DetachedCriteria. См. the docs для более подробной информации.
  • Вы не можете сделать декартовой продукт с критериями и фильтровать в разделе where. (Это работает только с HQL).
  • Подзапросы не могут быть добавлены в предложение from (потому что это приведет к декартовому продукту). Вы можете только поместить их в предложение where (, exists и т. Д.)
  • Возможно, вы можете начать с AnotherTable и перейти к SomeTable. Это может быть альтернативное решение.
+1

Я знаю группу по решению, но проблема в том, что в отчете реального мира мне нужно было бы группировать так много столбцов, что SQL значительно замедлит работу над тысячами записей, ну, возможно, я могу попытаться изучить источник NHibernate и внести свой вклад в этот день ... Теперь я буду использовать исходный SQL, спасибо за помощь. –

Смежные вопросы