365 messaggi dal 08 febbraio 2009
Salve a tutti.
Stavo ragionando a come usare correttamente i 3 livelli in un'applicazione.
Mi sto però perdendo...

Supponiamo di avere queste tre tabelle

Ordine -> Cliente -> Agente

Supponiamo inoltre che siano tutti in corrispondenza 1:N (1 agente N clienti, 1 cliente N ordini).


Il dubbio è questo:
Dove devo mettere le "join" fra le tabelle? Perché così "a naso" direi che debbano essere nella parte di accesso ai dati, perché è una join.
Dall'altra, però, è anche vero che rischio di fare delle join inutili, poiché se la UI non deve visualizzare dei dati, è inutile fare la join.
Allo stesso modo, però, se devo fare dei filtri nel BIZ (per esempio per dare ad un agente l'elenco solo dei suoi ordini), le join tornano ad essere necessarie.

Di suo allora pensavo di strutturare la cosa così:

DAL (livello 1): Mi torna una serie di IQueriable<T> (dove T è la classe relativa, Ordine/Cliente/Agente) senza eseguire alcun genere di join/filtri

BIZ (livello 2): Mi torna una serie di IQueriable<T> prendendo quelle del livello 1 e applicandogli i filtri necessari (es: filtro per agente come dicevo prima)

UI (livello 3): Sfrutta gli IQueriable<T> del livello 2 ed è lui che si fa le join che gli servono (così se voglio solo l'elenco dei clienti non faccio la join con gli agenti)

Di suo, però, non capisco come possa funzionare.
Per esempio, supponiamo che io sia l'agente 1.
Il BIZ mi deve dare solo gli ordini che io posso vedere.
Per darmi la IQueriable<Ordine> deve fare già la join con i clienti e con gli agenti per sapere se sono dell'agente 1.
A questa IQueriable la UI fa poi di nuovo le join con i clienti (e anche qui il BIZ deve tornarmi solo i miei, con tanto di join con gli agenti)&#8230;
Per cui, in un esempio banale, nello stesso IQueriable ci sono una marea di join sovrapposte&#8230;

Dove mi sto perdendo? Ho visto alcuni esempi di logica "applicata" (anche il vostro "casting"), però non ho capito a livello logico come si debba strutturare la cosa.

Grazie mille
5.610 messaggi dal 09 febbraio 2002
Contributi
ciao, non conosco l'architettura di Model Virtual Casting ma dato che non hai ricevuto risposte, provo lo stesso a scrivere la mia.

JoeRuspante ha scritto:

DAL (livello 1): Mi torna una serie di IQueryable<T> (dove T è la classe relativa, Ordine/Cliente/Agente) senza eseguire alcun genere di join/filtri

Questo è ok. Hai già pensato a quale ORM utilizzare? Dai un'occhiata a Entity Framework, ti eviterà l'incombenza di sviluppare un tuo DAL. Leggi questo articolo introduttivo di Stefano Mostarda:
http://www.linqitalia.com/articoli/entity-framework/introduzione-entity-framework.aspx
L'articolo che ti ho linkato è di 3 anni fa e da allora Entity Framework è stato arricchito con nuove funzionalità e con il supporto all'approccio Code First. Qui su Aspitalia trovi molti articoli, fai esperienza con questo ORM e vedrai che realizzare lo strato DAL sarà molto semplice.

JoeRuspante ha scritto:

BIZ (livello 2): Mi torna una serie di IQueryable<T> prendendo quelle del livello 1 e applicandogli i filtri necessari (es: filtro per agente come dicevo prima)

Mmh, no. Il filtro per agente, in questo caso, è logica di business che "trasuda" dal livello 2 fino alla UI e così facendo non avrai ben isolato i tre strati. Immagina che la UI non esista proprio e che l'agente possa interagire programmaticamente con il Business Layer. Devi impedirgli già lì, al livello 2, di accedere ai dati degli altri agenti dandogli come unico punto di accesso un metodo tipo GetMieiOrdini().
Il compito della UI deve essere semplicemente quello di visualizzare una struttura dati per mostrarla all'utente. Poi deve recuperare il suo input e restituire i dati modificati al livello business.

Il tipo restituito dai metodi del business layer può essere un banale IList<Ordine> oppure un IQueryable<Ordine> ma solo per consentire alla UI di ordinare, paginare e filtrare i dati. Ad ogni modo, dato che hai consultato l'applicazione Model Virtual Casting, leggi questo articolo di Cristian Civera che risponderà anche al problema che hai sollevato al punto 3.
http://blogs.aspitalia.com/ricciolo/post2690/LINQ-Lazy-Loading-Architettura.aspx

JoeRuspante ha scritto:

UI (livello 3): Sfrutta gli IQueryable<T> del livello 2 ed è lui che si fa le join che gli servono (così se voglio solo l'elenco dei clienti non faccio la join con gli agenti)

Entity Framework (come anche altri ORM) ha il concetto di "lazy loading", ovvero va a caricare le entità dipendenti (come gli Ordini contenuti nella classe Cliente) solo quando ti servono, effettuando una seconda SELECT in modo assolutamente trasparente quando vai a leggere la collezione. Volendo migliorare le prestazioni, la UI può, contestualmente alla richiesta dei Clienti, richiedere anche il caricamento della sua collezione Ordini (ne viene fuori una JOIN come chiedevi tu). Questo è lo scopo dell'extension method .Include di cui si parla nell'articolo.

Quindi, ricapitolando: il livello di business prepara una query LINQ su Clienti, magari usando l'extension method .Where per filtrare per agente e poi restituisce un IQueryable (o un suo derivato) alla UI che gli accoda un .Include per richiedere il caricamento degli Ordini e, opzionalmente, altri extension methods come .Skip e .Take per la paginazione.

ciao
Modificato da BrightSoul il 18 dicembre 2011 23.54 -

- So what you're saying is, if we get in trouble, there's no one to help us out?
- I'm afraid not.
- Fantastic!
365 messaggi dal 08 febbraio 2009
Grazie.

Per essere ho già deciso di usare Entity Framework col Code First (quindi l'ultima versione, così salvo casi particolari non mi devo sbattere più di tanto col DB).

Per la logica "di filtro" l'avevo messa pure io nel BIZ, forse non ci siamo capiti (ovvero il DAL restituisce tutti gli ordini, la BIZ decide quali possono essere visti dall'agente, la UI li visualizza nel modo che preferisce).

Grazie ancora
ovvero il DAL restituisce tutti gli ordini, la BIZ decide quali possono essere visti dall'agente
in che senso restituisce tutti gli ordini?
Nel DAL (repository) avrai il metodo GetMieiOrdini(IDAgente) che esegue un .Where(a => a.IDAgente == IDAgente)
Nel Biz avrai il metodoo GetMieiOrdini(xyz) che ricava l'id dall'utente Agente che ha fatto il login.

Altrimenti con un milione di ordini la query li restituisce tutti e poi vai a filtrare in base all'utente .... l'amministratore del DB ti amerà per una cosa simile

O forse ho capito male....

jQuery & Azure ... come ho fatto a stare senza fin'ora!

Non hai veramente capito qualcosa fino a quando non sei in grado di spiegarlo a tua nonna.
-Albert Einstein-
365 messaggi dal 08 febbraio 2009
Per essere hai capito male (o non ho capito bene io come funziona).
Se nel DAL ho un metodo con questa firma:

public IQueryable<Ordine> GetAllOrdini()
{
   // Questo è solo un esempio
   from o in db.Ordini
   select o;
}



che senso ha avere anche una "GetAllOrdiniByAgente"? In fondo ho già a disposizione un IQueryable, quindi nel BIZ potrei scrivere qualcosa del tipo:


from o in DAL.GetAllOrdini()
where o.idAgente == 1
select o




Già l'IQueryable dovrebbe garantire che il filtro venga fatto a livello di DB (ovvero al DB arriva già la query con in "WHERE ID_AGENTE = 1").

Mi chiedevo cosa potesse succedere se la UI esegue una query su un IQueryable del BIZ che a sua volta fa altre selezioni verso il DAL usando la medesima IQueryable.

Ho però fatto alcuni test e mi sembra di aver capito come funziona il tutto... Ed ora sto cercando di studiare un po' la soluzione del Model Virtual Casting (che stranamente mi diventa più comprensibile ogni giorno che passa!)

Grazie comunque!
Ho scritto in maniere poco chiara, faccio riferimento a ModelVC così non ci sbagliamo.

nel repository Candidate trovi
public IQueryable<Candidate> Where(Expression<Func<Candidate, bool>> predicate)


quindi nel biz userai candidateRepo.Where(x => x.yz)

PS: verifica sempre la query che viene inviata al db, c'è sempre il richio delle n+1 select ... come ho imparato in passato

jQuery & Azure ... come ho fatto a stare senza fin'ora!

Non hai veramente capito qualcosa fino a quando non sei in grado di spiegarlo a tua nonna.
-Albert Einstein-

Torna al forum | Feed RSS

ASPItalia.com non è responsabile per il contenuto dei messaggi presenti su questo servizio, non avendo nessun controllo sui messaggi postati nei propri forum, che rappresentano l'espressione del pensiero degli autori.
Community
Ultimi messaggi
UTENTI ONLINE
In primo piano

I più letti di oggi

Media
In evidenza
MISC