2009-09-03 16 views
6

sto fondamentalmente cercando di creare questa query con interfaccia NHibernate ICriteria:NHibernate 2.1: LEFT JOIN sul SubQuery con Alias ​​(ICriteria)

SomeTable 1: n AnotherTable

SomeTable ha colonne: PrimaryKey, NonAggregateColumn
AnotherTable ha colonne: 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 

È evidente che l'utilizzo della sottoquery Projection non è molto efficiente, dal momento che SQL deve eseguire la scansione della tabella due volte (una subquery di proiezione per aggregato).

L'utilizzo di più GROUP BY non è efficiente.

C'è una soluzione per questo? Finora mi sono ricorso all'utilizzo di SQL non elaborato, ma questo risulta ingombrante per report complessi.

+0

Puoi chiarire la tua domanda? La query che stai visualizzando è sql nativo. Ritorna già i dati previsti? Vuoi trasformarlo in criteri. Perché non HQL? –

+0

Hai dimenticato di menzionare: stai utilizzando un ORM. Quindi, per scrivere una query, non devi preoccuparti troppo dei tavoli e della chiave esterna. Molto più importanti sono le entità e le definizioni di mappatura. Quindi, come sono mappati questi ai tavoli? C'è una lista in SomeTable? C'è un riferimento in AnotherTable? O entrambi? –

+0

Sì, la query originale restituisce i dati necessari per un report. Sto usando NHibernate 2.1. L'API dei criteri è preferibile a causa dell'abilità di tipizzazione forte tramite NHLambdaExtensions (che sto anche utilizzando). Sto usando i nomi SomeTable, AnotherTable per rendere l'SQL chiaro e facile da leggere. È uno specchio fittizio di oggetti reali. L'oggetto mappato SomeTable ha una raccolta inversa uno-a-molti di oggetti AnotherTable. –

risposta

2

Sfortunatamente, i criteri sono un po 'limitati.

Prova questo:

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

Probabilmente bisogno di giocare un po 'intorno, è più di una congettura. Potrebbe anche essere impossibile in questo modo.

Dovrebbe produrre qualcosa di simile:

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 

generale:

  • È possibile effettuare sottointerrogazioni usando DetachedCriteria. Vedi the docs per maggiori dettagli.
  • Non è possibile creare un prodotto cartesiano con criteri e filtrare nella clausola where. (Funziona solo con HQL).
  • Non è possibile aggiungere sottoquery alla clausola from (poiché ciò comporterebbe un prodotto cartesiano). Puoi solo inserirli nella clausola where (in, exists ecc.)
  • Probabilmente potresti iniziare con AnotherTable e navigare fino a SomeTable. Questa potrebbe essere una soluzione alternativa.
+1

Sono a conoscenza del gruppo per soluzione, ma il problema è che nel rapporto del mondo reale, avrei bisogno di raggruppare da così tante colonne, che SQL rallenterà moltissimo per 1000s di record, vabbè, forse posso provare a studiare la fonte di NHibernate e contribuire a questo un giorno ... Userò SQL raw per ora, grazie per l'aiuto. –