2010-05-05 21 views
14

Ho un oggetto radice che ha una proprietà che è una raccolta.NHibernate Raccolta IQueryable come proprietà della radice

Ad esempio:

I have a Shelf object that has Books. 

// Now 
public class Shelf 
{ 
    public ICollection<Book> Books {get; set;} 
} 

// Want 
public class Shelf 
{ 
    public IQueryable<Book> Books {get;set;} 
} 

Quello che voglio realizzare è quello di restituire una collezione che è IQueryable in modo che possa funzionare paging e filtraggio fuori della collezione direttamente dal genitore.

var shelf = shelfRepository.Get(1); 

var filtered = from book in shelf.Books 
       where book.Name == "The Great Gatsby" 
       select book; 

voglio avere che query eseguita appositamente per NHibernate e non un ottenere tutto per caricare un'intera collezione e poi analizzarlo in memoria (che è ciò che attualmente succede quando uso ICollection).

Il ragionamento alla base di questo è che la mia raccolta potrebbe essere enorme, decine di migliaia di record, e una richiesta di ottenere tutte le query potrebbe bash il mio database.

Mi piacerebbe farlo implicitamente in modo che quando NHibernate vede un IQueryable sulla mia classe, sa cosa fare.

Ho esaminato il provider LINQ di NHibernate e attualmente sto prendendo la decisione di prendere grandi raccolte e dividerle nel proprio repository in modo da poter effettuare chiamate esplicite per il filtraggio e il paging.

LINQ to SQL offre qualcosa di simile a quello di cui sto parlando.

risposta

12

Ho cercato di trovare una soluzione per un problema simile.

È possibile filtrare le raccolte da un'entità utilizzando ISession.FilterCollection. Questo crea un IQuery aggiuntivo in cui puoi contare, pagina, aggiungere criteri, ecc.

Così, per esempio (la mia domanda in FilterCollection può essere un po 'fuori, ma si dovrebbe ottenere l'idea):

ISession session = GetSession(); 
var shelf = session.Get<Shelf>(id); 
var books = session.FilterCollection(shelf.Books, "where Name = :title").SetString("title", "The Great Gatsby").List<Book>(); 

Non ci sono problemi con questo, però:

  1. Il l'utente che esegue il codice deve accedere a ISION.CreateFilter oppure è necessario per creare un metodo sul repository che contiene una proprietà, una query e gli argomenti di query (oltre a qualsiasi paging o altre informazioni ). Non proprio la cosa più sexy sul pianeta.
  2. Non è il LINQ che volevi.

Sfortunatamente, non penso che ci sia un modo per ottenere ciò che si desidera fuori dalla scatola con NHibernate. Si potrebbe fingere, se si voleva provare, ma sembrano cadere piatto per me:

aggiungere un metodo o una proprietà che sotto le coperte restituisce un LINQ to NHibernate IQueryable per questo scaffale:

public IQueryable<Book> FindBooks() { 
    return Resolver.Get<ISession>().Linq<Book>().Where(b => b.Shelf == this); 
} 

dove qualcuno potrebbe consumare che in questo modo:

var shelf = ShelfRepo.Get(id); 
var books = (from book shelf.FindBooks() 
      where book.Title == "The Great Gatsby" 
      select book); 

Yuck! Stai perdendo le tue esigenze di persistenza attraverso il tuo modello di dominio! Forse si potrebbe rendere un po 'meno peggio di avere un repository emettono IQueryable, che in fase di esecuzione è in realtà LINQ to NHibernate:

public IQueryable<Book> FindBooks() { 
    return Resolver.Get<IRepository<Book>>().CreateQuery().Where(b => b.Shelf == this); 
} 

ancora piuttosto bla.

Crea il tuo tipo di raccolta personalizzato (e potenzialmente un'implementazione IQueryable) che racchiude un campo privato dei libri effettivi e mappa NHibernate in quel campo. Tuttavia, potrebbe essere un'impresa difficile farlo funzionare con ISession.CreateFilter. Devi considerare di "scoprire" la sessione corrente, convertire l'espressione LINQ in qualcosa che puoi usare in CreateFilter, ecc. Inoltre, la tua logica di business dipende ancora da NHibernate.

Niente di veramente soddisfacente a questo punto. Fino a quando NHibernate non può fare LINQ su una raccolta per te, sembra che tu stia meglio semplicemente interrogando il tuo repository di libri normalmente come è già stato suggerito, anche se non sembra sexy o ottimale.

+0

Grazie per essere stato così approfondito nella tua spiegazione. Ho pensato alle cose che hai detto, e sono d'accordo con tutti i punti che fai. Mi chiedo se NHibernate 3 supporti solo questo out of the box. –

1

Forse dovresti dare una prova a Nhibernate Linq. Esso consente di utilizzare l'IQueryable e fare le cose come:

Session.Linq<Book>().Where(b => b.Name == "The Great Gatsby"); 
+0

"Ho esaminato il provider di NHibernates Linq e attualmente sto prendendo la decisione di prendere grandi raccolte e dividerle nel loro repository in modo da poter effettuare chiamate esplicite per il filtraggio e il paging". –

+2

@ Khalid - Non so perché questo non ti aiuta. È esattamente quello che hai chiesto – Dann

+0

La mia domanda era "Come faccio a ottenere NHibernate per mappare su una proprietà IQueryable?" So già di NHibernate Linq. Questa è una risposta a una domanda che non ho mai chiesto ed è per questo che ho votato. –

3

tendo a pensare in questo modo:

radici di aggregazione sono i confini di coerenza, quindi se mensola ha bisogno di far rispettare una sorta di politiche di consistenza sui libri contiene, quindi dovrebbe essere una radice aggregata. E in tal caso dovrebbe contenere un set/collezione di libri.

Se non è necessario applicare la coerenza in alcun modo, dallo scaffale ai libri, quindi prenderei in considerazione la rimozione della proprietà set/collection e spostare quelle query in un repository.

Inoltre, poiché l'impaginazione e il filtro molto probabilmente non hanno nulla a che fare con la logica del dominio, è molto probabile per la presentazione. Quindi vorrei prendere in considerazione una vista speciale per questo invece di aggiungere facillities di presentazione ai miei repository.

ad es.

var result = Queries.FindBooksByShelf(shelfId,pageSize); 

Tale richiesta potrebbe tornare proiezioni e/o essere ottimizzato come SQL pianura ecc Essi sono molto probabilmente specifici per una certa visione o report nel GUI. In questo modo il tuo dominio si concentrerà solo sui concetti di dominio.

Problemi correlati