2009-09-03 15 views
6

jestem zasadniczo próbuje utworzyć kwerendy z interfejsem NHibernate ICriteria:NHibernate 2.1: LEFT JOIN na podzapytanie z Alias ​​(ICriteria)

SomeTable 1: N AnotherTable

SomeTable ma kolumny: primaryKey, NonAggregateColumn
AnotherTable ma kolumny: 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 

Jest oczywiste, że użycie podzapytania Projekcja nie jest bardzo wydajne, ponieważ SQL musi skanować tabelę dwa razy (jedno podzapytanie na agregat).

Używanie wielu grupowych grup użytkowników również nie jest wydajne.

Czy istnieje rozwiązanie tego problemu? Do tej pory używałem surowego SQL, ale staje się ono nieporęczne w przypadku złożonych raportów.

+0

Czy możesz wyjaśnić swoje pytanie? Zapytanie, które wyświetlasz, to natywny sql. Czy już zwraca oczekiwane dane? Chcesz zmienić to na kryteria. Dlaczego nie HQL? –

+0

Zapomniałem wspomnieć: używasz ORM. Tak więc, aby napisać zapytanie, nie musisz troszczyć się zbytnio o tabele i klucz obcy. O wiele ważniejsze są encje i definicje mapowania. Więc w jaki sposób są one mapowane? Czy istnieje lista SomeTable? Czy istnieje odniesienie w AnotherTable? Lub oba? –

+0

Tak, pierwotne zapytanie zwraca potrzebne dane do raportu. Używam NHibernate 2.1. API Kryteriów jest preferowany ze względu na silne umiejętność pisania za pomocą rozszerzenia NHLambda (którego również używam). Używam nazw SomeTable, AnotherTable, aby SQL był przejrzysty i czytelny. To fikcyjne zwierciadło prawdziwych przedmiotów. Obiekt odwzorowany SomeTable ma odwrotną jeden-do-wielu zbiór obiektów AnotherTable. –

Odpowiedz

2

Niestety Kryteria są nieco ograniczone.

Spróbuj tego:

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[]>(); 

Prawdopodobnie trzeba poeksperymentować trochę, to bardziej chyba. To też może być niemożliwe w ten sposób.

Należy stworzyć coś takiego:

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 

Ogólnie:

  • można dokonać za pomocą podzapytania DetachedCriteria. Aby uzyskać więcej informacji, patrz the docs.
  • Nie można utworzyć produktu kartezjańskiego z kryteriami i filtrować w klauzuli where. (Działa tylko z HQL).
  • Podzapytanie nie może być dodane do klauzuli "od" (ponieważ spowoduje to powstanie produktu kartezjańskiego). Możesz wstawić je tylko do klauzuli where (in, exists).
  • Najprawdopodobniej możesz zacząć od AnotherTable i przejść do SomeTable. To może być alternatywne rozwiązanie.
+1

Jestem świadomy grupy za pomocą rozwiązania, ale problem polega na tym, że w raporcie na temat świata rzeczywistego musiałbym pogrupować według tak wielu kolumn, że SQL zwolni wiele z tysięcy rekordów, no cóż, może mógłbym spróbować zbadać źródło NHibernate i przyczynić się tego jednego dnia ... Na razie używam surowego SQL, dziękuję za pomoc. –