Repository Pattern: ok, fucilatemi...

rated by 0 users
This post has 27 Replies | 5 Followers

Top 25 Partecipanti
Post 44
Punteggio 685

Ciao a tutti,
Scusate l'intromissione...

>perch� molto probabilmente i criteri di filtro sono sugli attributi del
>documento e non spaziano in relazioni che possono annidarsi in maniera
>intricatissima... voglio tutti i clienti il cui fatturato � superiore a
>"x" nel periodo "y" con sede legale nel cap "z" ma con destinazione
>della merce nel cap "k".. ecco questo con un repository faccio un po'
>fatica a pensarlo, mentre in questo scenario mi viene molto bene
>applicare lo specification pattern e avere un solo entry point allo
>storage, come ad esempio � la session di NH. 
Ciao Mauro,
come ti comporteresti invece nel caso più complesso dove non gradisci IRepository?
Ciao

  • | Punteggio Post: 20
Top 25 Partecipanti
Maschio
Post 67
Punteggio 1.440

io in questo caso uso un approccio idiomatico che ho definito "LET" (acronimo di: "Layered Expression Trees"): in pratica, la mia interfaccia IRepository<T> estende IQueryable<T>, quindi restituisce un insieme "virtuale" di istanze delle entità di dominio. L'idea è che ogni servizio/layer arricchisce/compone la query restituita dal repository sotto forma di IQueryable, facendo affidamento sul fatto che la deferred execution di LINQ mi assicura che la query sarà eseguita solo all'ultimo momento ed includerà solo quanto effettivamente necessario. 

Dal punto di vista pratico, hai tutti i vantaggi delle specification senza però l'aggravio (poco o tanto che sia) di dovertele implementare, unito alla possibilità di costruirti a costo zero query "pret a porter" :-)

Purtroppo, questo idioma richiede che il LINQ provider sia valido, ed al momento NH su questo fronte è "sofferente", in attesa della V3.

 

Top 25 Partecipanti
Post 44
Punteggio 685

Mmm...diciamo che ho capito e scriviamo di no. :-(
Ti chiederei qualche esempietto ma temo di portare ancora più confusione nella mia testa.

Resto in topic parlado di IRepositoriu su NSK.
Sto cercando di "studiarlo" un po' ma ho qualche difficoltà perché rispetto al tuo libro ci sono un po' di modifiche che non riesco a seguire molto bene. 
Visto che sei "qui" ti pongo una domanda proprio su IRepository e più precisamente sull' IOC che li riguarda perché vorrei togliermi una curiosità.
Io guardo ad NSK come se fosse una applicazione di grosse dimensioni...
Quello che mi spaventa (magari erroneamente) è tutta la configurazione per tutti quei repositori che alla fine faranno parte del solito assebly(/modulo) .
Mmm... provo a spiegarmi meglio perché non mi capisco da solo.
Non sarebbe fattibile(e se si quanto sarebbe sensato) una specie di repository factory per ogni modulo? Il factory poi sarebbe quello da iniettare tramite IOC. Una cosa tipo ICoreRepositoryFactory la cui implementazione restituisce tutti i vari repository (ICustomerRepository,ICategoryRepository,...) ha senso una cosa del genere?

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907
Ciao Andrea,

andysal wrote:
[cut]
> Purtroppo, questo idioma richiede che il LINQ provider sia valido, ed al
> momento NH su questo fronte è "sofferente", in attesa della V3.
[cut]

Uh? In che senso?
Non facciamo scherzi, eh... ;-/

Ciao,
petrux

--
  • | Punteggio Post: 20
Top 25 Partecipanti
Maschio
Post 67
Punteggio 1.440

nel senso che, ad oggi, se vuoi avere la ragionevole certezza che una query LINQ funzioni con l'attuale provider per NH, il tipo degli elementi della sequenza in ingresso deve coincidere con quello della sequenza in uscita. Per intenderci, una "roba" del tipo:

from c in CustomerRepository select c.Party

a runtime ti restituisce un errore di cast... AFAIK uno degli obbiettivi della v3 di NH consiste proprio nel fornire un provider LINQ di buona qualità...

Top 25 Partecipanti
Maschio
Post 67
Punteggio 1.440

come "esempietto", prova a guardare in NSK la funzionalità di ricerca prodotti/categorie: il controller chiama il worker service, che "chiude" l'IQueryable sul ViewModel (e questo è Model 3). Il Worker Service chiama un servizio sul business layer (ProductServices, che ha la responsabilità di "decidere" quali siano i prodotti da considerare "vendibili") che fa una query sul Repository. Fino al Worker Service, ciò che "viaggia" tra servizi/layer è un IQueryable (e questo è LET)

In quanto a NSK, credo che farò un post per spiegare la situazione: in breve, cmq, il libro riflette una codebase ormai datata (ossia quella che avevo a disposizione mentre lo scrivevo, ormai oltre 2 anni addietro). Terminato il libro, ho ripreso ad occuparmi dei progetti di Managed Designs, quindi ho "sperimentato ed applicato" nuove soluzioni, che pian piano ho "backportato" (non ancora completamente) in NSK. L'architettura attuale di NSK "dovrebbe" essere alla base della seconda edizione del libro, della quale io e Dino abbiamo già iniziato a "chiacchierare" (ma che non abbiamo ancora iniziato a scrivere)

.A

Top 25 Partecipanti
Post 44
Punteggio 685

Ok. Proseguo con lo studio di NSK.
p.s.:
non vorrei averti offeso con la parola "esempietto" :-)

p.p.s.:
Cosa mi dici a proposito dell'altra domanda su IRepository di NSK. A proposito di 1 Repository x ogni entity ed un IOC per ogni repository?
Ha senso la mia perplessità o è totalmente insensata?

  • | Punteggio Post: 5
Top 25 Partecipanti
Post 44
Punteggio 685

Sempre a proposito di Repository pattern...
Cercando risposta a questo mio altro dilemma (http://www.guisa.org/forums/t/235.aspx) sono incappatto in questo post  http://msdn.microsoft.com/en-us/ff714955.aspx che tocca anche l'argomento di questo topic.
Cosa ne pensate di quelle implementazioni di IRepository (e visto che ci sono della UnitOfWork) ?.
Tralascio le mie osservazioni sulla UnitOfWork perchè ho solo delle "sensazioni" e devo ancora chiarire dei dubbi su questo pattern.
Ma per quanto riguarda il Repository ci sono due impelemtazioni:
-La prima non mi piace perché è troppo legata a EF4.
-La seconda mi piace perchè è unica . Cioè un Repository generico per tutte le entità.
A questo proposito mi piacerebbe adottare 2 soluzioni in una cioè: un repository generico per le entità più semplici ed uno specifico per ogni entità complessa.

Al solito... hanno senso secondo voi queste considerazioni?Cosa ne pensate?

Ciao

  • | Punteggio Post: 20
Top 25 Partecipanti
Maschio
Post 30
Punteggio 678

Ciao,
ultimamente sto lavorando su un progetto abbastanza articolato, in quanto deve integrarsi con un'altra applicazione in uso dal cliente tramite un'SDK proprietario della società che ha realizzato l'altra applicazione. Manco a dirlo, l'architettura del suddetto SDK non segue alcuno dei "principi" S.O.L.I.D., non da supporto per le transazioni, ne tantomeno implementa un provider LINQ.

ll dominio dell'applicazione è quindi per forza di cose splittato in 2:

  • una parte, corrispondente alle entità specifiche del mio sistema, la cui persistenza è mantenuta in un db custom
  • una parte, corrispondente alle entità del sistema con cui mi vado ad integrare, la cui persistenza è gestita totalmente dall'applicazione legacy, via SDK

ho pensato quindi di strutturare le cose in questo modo:

  • Il dominio è costituito da classi POCO, ed è "virtualmente" partizionato in due sottodomini
  • Le relazioni tra le classi appartenenti ai due sottodomini sono implicite (ovvero, non utilizzo proprietà di collegamento, ma solo campi "chiave")
  • Ho definito un tipo di repository (interfacce... IUserRepository, IActivityRepository, ...) per ogni "radice aggregata" del mio dominio
  • L'implementazione concreta di ogni repository è strettamente correlata al framework delegato a gestire la persistenza di quella specifica entità.
    • La persistenza delle entità del mio sistema è gestita tramite NHibernate, quindi i repository ad esse dedicate avranno un riferimento alla session di NHibernate (o meglio, ad un INhSessionProvider iniettato via IoC)
    • La persistenza delle entità appartenenti al sistema legacy è gestita tramite l'SDK proprietario, che ha anch'esso un concetto di Session. I repository ad esse dedicate avranno un riferimento ad un ILegacySessionProvider (anche questo, iniettato via IoC) che gli fornisce (un wrapper per) la session con cui effettuare le letture/scritture.

Le sessioni sono attivate on-demand, mentre il Dispose e eseguito da un HttpModule custom all'atto dell'invio della response. Questo tipo di modello ci ha letteralmente "salvato la vita" quando ci siamo resi conto che il caricamento puntuale (il solito GetById, per intenderci) di alcune tipologie di entità appartenenti al sistema legacy era troppo oneroso (non tanto per la chiamata in se, ma per il grosso numero di chiamate consecutive necessarie all'esecuzione di determinate procedure)...

Ridefinendo i soli repository impattati dal rallentamento, abbiamo potuto introdurre facilmente una cache su cui redirigere le richieste di accesso ai dati. Essendo i repository concreti "passati" ai servizi che li utilizzano via IoC, è stato sufficiente modificare la configurazione di Ninject  per switchare dal sistema "rallentato" a quello "maximum speed"... ed abbiamo comunque mantenuto la possibilità di tornare indietro in qualunque momento (nel caso riscontrassimo dei bug nel sistema di gestione della cache, ad esempio), in quanto i repository definiti prima del refactoring sono ancora lì, pronti all'uso.

neronotte

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 268
Punteggio 4.907
Ciao andysal,

andysal wrote:
> AFAIK uno degli obbiettivi
> della v3 di NH consiste proprio nel fornire un provider LINQ di buona
> qualità...

Sto giusto per fate svn checkout sul trunk di NHibernate... ;-)

Ciao,
petrux
--
  • | Punteggio Post: 5
Top 25 Partecipanti
Post 44
Punteggio 685

Mmm... eppure mi sfuggono/non capisco alcune cose.
Prendo per esempio un gestionale perchè è il mondo a me più vicino.
Spesso ho l'impressione che il 50%(se non di più) delle entità che lo compongono siano di livello "semplice" alcune mooolto semplice.
Possibile che sia meglio costruirsi un infrastruttura di Repository (interfaccia + implementazione) per ogni entità  considerando quanto dtto sopra?
Quello che apprezzavo del post linkato era il repositori ad uso generico per queste ragioni.
Anagrafica nazioni,valute,banche,lingue,clienti,fornitori ecc...in genere tutte le entita di tipo "anagrafico" sono piuttosto semplici, possibile avere una configurazione di IOC lunga 2 Km per entità di questo livello?
Non è meglio una cosa del genere :
IRepository<T>: ....   where T :IDomainEntity   (l'interfaccia repository di base)
quindi una implementazione Repository<T>:IRepository<T> che sarà comune alle entità semplici e magari ereditato da quelle più complesse. ?

Stessa logica lato services Interfaccia e implementazione ad uso generico più specifiche implementazioni per entità più complesse.

Spero di essermi spiegato...bene.
Cosa ne pensate ?
Saluti

  • | Punteggio Post: 20
Top 10 Partecipanti
Maschio
Post 243
Punteggio 3.383

Per ridurre la configurazione di IOC si può usare la registrazione by convention. Ovvero ad esempio se tu hai una serie di servizi, tutti chiaramente che vanno registrati, puoi dire a Castle di registrare tutte le classi di un certo assembly che implementano una interfaccia marker tipo (IService) oppure tutti quelli che finiscono in Service etc etc.

Se la registrazione è più complessa, puoi farti una facility che registra sulla base di un attributo, in questo caso io decoro una classe con un attributo che fa in modo di autoregistrare la classe senza configurazione, ma poi in questo modo è più complicato gestire gli intercettori etc etc.

Solitamente comunque il repository, per lo meno come lo ho sempre fatto io, è registrato di base con il generic, ovvero registri solo il repository<T>, e poi puoi registrare alcune versioni specifiche per entità il cui repository magari è differente da quello base. Ma in generale più tieni semplice il file di configurazione di IoC più vivi meglio. :)

Alk.

  • | Punteggio Post: 20
Top 25 Partecipanti
Post 44
Punteggio 685

Perfetto quindi no ero fuori strada. Grazie...

  • | Punteggio Post: 5
Pagina 2 di 2 (28 elementi) < Indietro 1 2 | RSS
Powered by Community Server (Commercial Edition), by Telligent Systems