2009-09-03 8 views
6

ich im Grunde mit NHibernate ICriteria Schnittstelle diese Abfrage zu erstellen versuchen:NHibernate 2.1: LEFT JOIN auf SubQuery mit Alias ​​(ICriteria)

Sometable 1: n AnotherTable

Sometable hat Spalten: PrimaryKey, NonAggregateColumn
AnotherTable hat Spalten: 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 

Es ist klar, dass die Verwendung der Projection-Unterabfrage nicht sehr effizient ist, da SQL die Tabelle zweimal scannen muss (eine Projektionsunterabfrage pro Aggregat).

Die Verwendung mehrerer GROUP BYs ist ebenfalls nicht effizient.

Gibt es dafür eine Lösung? Bis jetzt habe ich auf Raw SQL zurückgegriffen, aber das wird für komplexe Berichte unhandlich.

+0

Können Sie Ihre Frage klären? Die Abfrage, die Sie anzeigen, ist native SQL. Gibt es bereits die erwarteten Daten zurück? Sie möchten es in Kriterien umwandeln. Warum nicht HQL? –

+0

Vergessen zu erwähnen: Sie verwenden ein ORM. Um also eine Abfrage zu schreiben, müssen Sie sich nicht zu sehr um die Tabellen und den Fremdschlüssel kümmern. Viel wichtiger sind die Entitäten und Mapping-Definitionen. Wie werden diese auf Tabellen abgebildet? Gibt es eine Liste in SomeTable? Gibt es eine Referenz in AnotherTable? Oder beides? –

+0

Ja, die ursprüngliche Abfrage gibt die erforderlichen Daten für einen Bericht zurück. Ich benutze NHibernate 2.1. Die Kriterien-API wird wegen der starken Tippfähigkeit über NHLambdaExtensions (die ich auch verwende) bevorzugt. Ich verwende die Namen SomeTable, AnotherTable, um die SQL klar und einfach zu lesen. Es ist ein fiktiver Spiegel realer Objekte. Das zugeordnete SomeTable-Objekt verfügt über eine inverse Eins-zu-Viele-Auflistung von AnotherTable-Objekten. –

Antwort

2

Leider ist Kriterien ein bisschen eingeschränkt.

Try this:

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

Sie müssen wahrscheinlich ein wenig herum spielen, ist es eher eine Vermutung ist. Es könnte auch so unmöglich sein.

Es sollte wie folgt produzieren:

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 

Allgemein:

  • Sie Subqueries DetachedCriteria mit machen kann. Weitere Informationen finden Sie unter the docs.
  • Sie können kein kartesisches Produkt mit Kriterien erstellen und in der where-Klausel filtern. (Dies funktioniert nur mit HQL).
  • Unterabfragen können nicht zur from-Klausel hinzugefügt werden (da dies zu einem kartesischen Produkt führen würde). Sie können sie nur in die Where-Klausel (in, exists etc.) setzen.
  • Sie könnten wahrscheinlich mit AnotherTable beginnen und zu SomeTable navigieren. Dies könnte eine alternative Lösung sein.
+1

Ich kenne die Gruppe nach Lösung, aber das Problem ist, dass ich in der realen Welt Bericht nach so vielen Spalten gruppieren müsste, dass SQL eine Menge für 1000s von Aufzeichnungen verlangsamen wird, na ja, vielleicht kann ich versuchen, die Quelle von NHibernate zu studieren und einen Beitrag dazu zu leisten ... Ich werde jetzt Raw SQL verwenden, danke für die Hilfe. –