2011-02-07 16 views
8

Ho un'applicazione che utilizza alcuni principi di data warehousing come la modellazione dimensionale per fare report su un database abbastanza semplice.Query statistica in SQL - questo è possibile con NHibernate LINQ?

Un esempio (semplificato) entità denominata chiamata si presenta così:

public virtual long Id { get; set; } 
    public virtual string OriginatorNumber { get; set; } 
    public virtual string DestinationNumber { get; set; } 
    public virtual DateDimension DateDimension { get; set; } 

Alcune delle proprietà del modello reale sono stati rimossi in quanto sono irrilevanti. Il DateDimension semplificato simile al seguente:

public virtual long Id { get; set; } 
    public virtual DateTime Date { get; set; } 
    public virtual int DayOfMonth { get; set; } 
    public virtual int Weekday { get; set; } 

Ci sono molte più colonne come questo - sono precompilato per il decennio in corso per l'installazione dell'applicazione. Quindi ogni data nell'intero decennio ha una riga in questa tabella e ogni chiamata ha un link alla data in cui è avvenuta. Tutto questo è mappato su Fluent NHibernate e funziona bene.

Se voglio fare un po 'di segnalazione, posso farlo facilmente con il migliorato fornitore LINQ di NHibernate in 3.0. Vorremmo usare LINQ per la migliorata manutenibilità che ci offre, ma se davvero dovessimo, prenderemo in considerazione HQL, ICriteria o anche SQL semplice.

Quindi dire che voglio creare un rapporto che mostri il numero di chiamate da un certo numero, diviso per il giorno della settimana in cui si verificano. Posso farlo facilmente in questo modo:

 var query = Calls 
      .Where(c => c.OriginatorNumber == "402") 
      .GroupBy(c => c.DateDimension.Weekday) 
      .Select(g => new { Day = g.Key, Calls = g.Count() }); 

In questo esempio, "Calls" è fondamentalmente un IQueryable restituito dal fornitore NHibernates LINQ (Query) attraverso un'interfaccia repository. La query sopra mi dà i risultati corretti, NHibernate Profiler mi mostra che l'SQL è piuttosto ottimale, tutto va bene.

Tuttavia, se voglio fare qualcosa di leggermente più avanzato, mi blocco. Dire che voglio il numero medio di chiamate per giorno della settimana. Non troppo lontano da quanto sopra, giusto? Devo solo calcolare il numero di date uniche che ogni giorno della settimana ha nel set di risultati, dividere il numero totale di chiamate da esso, e siamo tutti a posto - giusto? Bene, no, questo è dove comincio a colpire i limiti del provider LINQ di NHibernate. Con LINQ to Objects ho potuto costruire una query per farlo - qualcosa sulla falsariga di

.Select(g => g.Count()/g.GroupBy(c => c.DateDimension.Date).Count()); 

Tuttavia, questo non converte nella query corretta quando lo si utilizza in NHibernate. Piuttosto, converte entrambe le chiamate .Count() nello stesso conteggio (*) dei record delle chiamate, quindi il risultato è sempre 1.

I COULD ovviamente basta interrogare per ogni chiamata, giorno della settimana e data come nuovo oggetto anonimo, quindi fare i calcoli sul lato dell'applicazione, ma secondo la saggezza convenzionale, That's Just Wrong (tm). Potrei finire per farlo nella disperazione, anche se ciò significa dolore quando il tavolo cresce fino a un milione di chiamate ++.

Il seguente è una query SQL che mi dà il risultato che sto cercando.

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 

E 'possibile farlo con il provider LINQ di NHibernate? Oppure, se ciò non è possibile, quanto posso avvicinarmi prima di dover consentire all'applicazione di recuperare il risultato intermedio e fare il resto?

+0

Forse stai andando nella direzione sbagliata. Che ne dici di creare uno schema a stella e precompilare le misure calcolate? – epitka

+0

Bene, questo è un punto interessante - tuttavia, la mia comprensione è che ogni entità nella tabella dei "fatti" (ad esempio, le chiamate nel mio esempio) ha un FK per ciascuna tabella delle dimensioni pertinente. Come posso creare uno schema a stella che mi aiuti a capire la data di scadenza delle chiamate e ad indicarlo da ogni record di chiamata? Ma in generale, sono molto aperto alla possibilità che io vada su questo nel modo sbagliato. :) –

risposta

1

Ci sono molte cose che non si possono fare con il provider LINQ. Usare HQL o CreateCriteria è solo qualcosa che dovrai accettare con NHibernate.

Non l'ho provato, ma sembra che si dovrebbe essere in grado di fare ciò che si vuole fare usando HQL o CreateCriteria (con DetatchedCriteria).

Se sei disperato, puoi anche tornare a SQL semplice utilizzando CreateSqlQuery.

+1

Ciao, e grazie per la tua risposta. Sì, potrei dover ricorrere a questo - il problema è fondamentalmente che volevo presentare ai miei utenti un'API basata su IQueryable , in modo che potessero fare qualche filtraggio con Where() prima di passarmi l'IQueryable per il raggruppamento. Sarebbe stato molto elegante - credo che quello che dovrei fare davvero è diventare un grande programmatore e contribuire a NHibernate. :) Grazie per l'input, esaminerò i modi di fare HQL e ICriteria. –