2009-03-30 9 views
19

Sto proponendo NHibernate per un progetto che stiamo facendo nella mia azienda e mi piacerebbe sapere se NHibernate può essere ottimizzato per recuperare solo colonne specifiche su una tabella quando si utilizza il linguaggio di query Criteri.Richiama solo colonne specifiche quando si utilizzano le query di criteri?

Ad esempio. Diciamo che ho una tabella con 30 colonne e questo è mappato su un oggetto usando NHibernate che è una corrispondenza 1 per 1 contro la tabella. Tuttavia, per una particolare funzione del sistema mi interessa solo due di queste colonne.

Ora, so che posso usare HQL e fare un CreateQuery che lo compirà ma che richiede di creare un costruttore per ciascuna combinazione di campi che vorrei recuperare in modo selettivo. Questo potrebbe essere un enorme problema dal punto di vista della manutenzione poiché non catturerò i costruttori mancanti fino al runtime.

Mi piace il linguaggio di query Criteria poiché genera SQL parametrizzato anziché query SQL dirette da HQL. Vedo che esiste un modello "Escludi" per non includere determinate colonne ma nella maggior parte dei casi includerò più colonne di quelle di esclusione.

Grazie al commento qui sotto ho esaminato le proiezioni e questa non è ancora la situazione ideale per me. Quando si utilizza il seguente:

var list = session 
    .CreateCriteria(typeof (Task)) 
    .SetProjection(Projections 
         .ProjectionList() 
         .Add(Projections.Property("Id"))) 
    .List(); 

io alla fine con le variabili list solo di essere interi, preferisco avere il mio oggetto piena attività, ma con tutti i campi impostati ai valori di default. È possibile? Tutto ciò che vedo finora dice no.

+0

Si prega di consultare l'aggiornamento al mio post in risposta alla domanda. – Danielg

risposta

34

Sì, è possibile farlo con query di criteri utilizzando le proiezioni. Basta proiettare solo le proprietà che si desidera utilizzare e solo quelle saranno incluse nella clausola select della query compilata.

http://nhibernate.info/doc/nh/en/index.html#querycriteria-projection

Update per modificare

Ci sono diversi modi per ottenere questo risultato, con alcune limitazioni tuttavia. 1) Il modo NHibernate.

var list = session.CreateCriteria(typeof (Task)) 
.SetProjection(Projections.ProjectionList() 
        .Add(Projections.Property("Name"), "Name") 
        .Add(Projections.Property("ID"), "ID") 
) 
.SetResultTransformer(Transformers.AliasToBean(typeof (Task))) 
.List(); 

Basta assegnare il nome della proprietà come un alias per la vostra proiezione e il trasformatore AliasToBean mapperà le proiezioni ad una classe reale. La limitazione a questo metodo è che qualsiasi proprietà che si mappa deve avere un setter nella classe POCO, questo può essere un setter protetto ma deve avere un setter.

si può anche fare questo con LINQ come pure in modo un po 'diverso

var list = session.CreateCriteria(typeof (Task)) 
.SetProjection(Projections.ProjectionList() 
        .Add(Projections.Property("Name")) 
        .Add(Projections.Property("ID")) 
) 
.List<IList>() 
.Select(l => new Task() {Name = (string) l[0], ID = (Guid) l[1]}); 

Questo è semplicemente utilizzando LINQ per mappare l'elenco indicizzato che è ouput in una nuova istanza della classe Task. La stessa limitazione di cui sopra si applica tranne che questo è un po 'più severo in quanto tutte le proprietà mappate devono avere un setter pubblico perché questo è ciò che linq usa per riempire l'oggetto.

Spero che questo ti aiuti.

+0

Si prega di consultare il mio aggiornamento alla domanda originale –

0

Non sono sicuro se questo sarà soddisfare i vostri scopi, ma questo è solo un suggerimento: se la query finisce per essere qualcosa che si sempre uso in ogni caso, è possibile creare uno SQL View per esso, quindi creare un mappare il file contro la vista.

NHibernate considera la vista come se fosse una qualsiasi tabella, anche se, naturalmente, le operazioni CRUD sarebbero un problema di fronte ai problemi di integrità dei dati.

5

In risposta alla vostra modifica: Per quanto ne so, questo non è possibile.

Ma, cosa si può fare, è creare una classe che è conosciuto da NHibernate, e che solo contiene le proprietà che vi interessano.

Per esempio, Classe A 'TaskView', che contiene solo alcune proprietà della classe 'Task'.
È necessario "importare" la classe TaskView in un file hbm.xml, in modo che NHibernate conosca questa classe (vedere la mappatura dell'importazione).
Quindi, è possibile utilizzare una proiezione per convertire l''attività' in un'istanza di TaskView. Quando si esamina la query generata da NHibernate, si vedrà che recupererà solo le colonne necessarie per popolare la classe TaskView.

Qualcosa come ho postato anche qui: NHibernate and Collection Counts

+0

Se aiuta il poster originale - Summer of Nhibernate Screencast 2a mostra questo approccio esatto IIRC. http://unhandled-exceptions.com/blog/index.php/2008/06/26/summer-of-nhibernate-session-02a-exploring-query-methods-and-syntaxes-cont-screencast-is-available/ –

0

Hai provato impostare il costruttore di default per impostare i valori di default? Dato che si tratta di un problema relativo all'applicazione, è compito dell'utente risolvere il problema. A proposito, perché hai bisogno di un costruttore per ogni permutazione? Hibernate utilizzerà il costruttore di tutti gli argomenti o il costruttore senza argomenti e quindi utilizzerà i setter, quindi non è necessario eseguire tutte queste operazioni. In realtà può fare molto di più se richiamo correttamente può anche impostare tutti i campi privati ​​senza setter se configurato correttamente tramite la magia di manipolazione del codice byte.

-1

Ho fatto una domanda simile e NHibernate sembra mancare della funzionalità più comune utilizzata dalle applicazioni dalla creazione di SQL. La possibilità di selezionare solo alcune colonne. Questo è davvero banale e se fossi stato nel progetto avrei rifiutato qualsiasi logica che richiedesse di saltare attraverso un cerchio e capovolto e tutto intorno solo per selezionare solo i campi. Anche se c'è una risposta, trovo le ore di ricerca troppo complicate per qualcosa di così semplice. So che è disponibile nel provider linq di Nhibernate utilizzando la proiezione, ma per query estremamente complesse non è possibile selezionare solo campi specifici. O tutti o devi iniziare a creare DTO/Modelli che non sono quelli originali che a mio avviso non dovrebbero essere duplicati perché un utente vuole solo meno record. Un elenco di esclusione/inclusione per le query regolari basate su SQL (non su linq) è obbligatorio. Vorrei che questi ORM facessero prima le cose basilari. Basta ignorare la compilazione del modello se i campi non vengono restituiti nel set di risultati dal database. Spero che qualcuno possa dare una soluzione semplice/hack/soluzione alternativa.

+0

Penso che sia una soluzione incredibilmente elegante e risolva completamente la mia domanda. NH fornisce questo meccanismo e lo fa bene. Questo è stato chiesto originariamente prima di NH 3.0 quando è diventato ancora più facile. –

+0

Sì, è elegante avere una proiezione. Ma non essere in grado di scegliere colonne parziali invece di un modello completo è ciò di cui stavo parlando per query SQL native. Vedi http://stackoverflow.com/questions/22889128/select-fields-on-some-tables-and-only-specific-fields-in-other-tables-to-mappe – SamMan

+0

Odd poiché la mia domanda iniziale riguardava le query sui criteri nello specifico. Avendo fatto più nh (e anche qualche altro orco domestico) ti raccomando di non usare mai query sql dirette. Nel peggiore dei casi dovresti usare SP e non ho mai visto un argomento valido per incorporare sql nel tuo codice in questo modo. –

Problemi correlati