Architettura: sto facendo le cose per bene?

6

Sto cercando di utilizzare un arco a strati "classico" usando .NET e Entity Framework. Stiamo iniziando da un database legacy che è un po 'schifoso:

  • Denominazione incoerente
  • Visualizzazioni non necessarie (vista che fa riferimento ad altre visualizzazioni, select * viste ecc ...)
  • Colonne aggregate
  • Patate e carote nella stessa tabella
  • ecc ...

Così ho concluso con l'isolamento completo della struttura del mio database dal mio modello di dominio. Per fare ciò le entità EF sono nascoste dal livello di presentazione. L'obiettivo è consentire un più facile refactoring del database riducendo al contempo l'impatto di esso sulle applicazioni.

Orastoaffrontandomoltesfideestoiniziandoachiedermisestofacendolecoseperbene.

  1. Ilmiomodellodidominioèaltamentevolatile,continuaaevolversiconleappinseguitoall'aumentodeinuovicampi.Lacomplessitàdiessocontinuaacrescereelaclasseincuiessacontieneiniziaaotteneremolteproprietà.

  2. CreareunastrategiadiinclusioneeriproiettaresuEFèmoltocomplicato(imieioggettididominiononhannoalcuntipodiproprietàdirapportodicaricamentopigro/ansioso):

    DomainInclude<Domain.Model.Bar>.Include("Customers").Include("Customers.Friends")
    // To...
    IFooContext.Bars.Include(...).Include(...).Where(...)
    
  3. Alcuni framework stanno violando i livelli di isolamento (Devexpress Grids che richiede XPO o IQueryable per il filtraggio e il paging di set di dati di grandi dimensioni)

Sto iniziando a chiedermi se:

  • l'isolamento delle entità generate automaticamente da EF è un costo non necessario.
  • Dovrei consentire ai framework di colpire IQueryable ? Pendenza lenta all'inferno? (è davvero difficile isolare il framework DevExpress, qualsiasi esperienza di successo?)
  • Come posso ridurre la volatilità del mio modello di dominio?

Precisazioni

Isolamento EF e campi che dovrebbero o non dovrebbero essere inclusi nelle chiamate di servizio

Ecco come isolare le Entità EF. Il livello di presentazione è un livello di isolamento in quanto nessuna presentazione può accedere alla classe repository.

// Inside a service class. For this sample Customer is defined in the service model
// And Person is autogenerated by Entity Framework
/// Get the customers who bought an item ///
IEnumerable<Customer> GetCustomers(Item item){
    var query = from person in _personRepository.GetItemBuyers(item.Id)
                select new Customer {
                  Id = person.CustomerId
                  , FirstName = person.FirstName
                  , LastName = person.LastName
                  , Sex = person.Sex == 'M' ? Sex.Male : Sex.Female};
    return query;
}

Può richiedere molto tempo soprattutto quando è necessario includere (o meno) alcune proprietà di relazione. Esistono diverse soluzioni per includere:

 1. GetCustomersWithOrders(Item item); 
 2. GetCustomers(Item item, IncludeStrategy<Customer> include);
 3. GetCustomers(Item item, params string[] fieldsIncluded);
  1. Otterrai risultati nella classe di servizio contenente migliaia di GetCustomersWith ... With ...
  2. Creerà molta classe ereditata da IncludeStrategy. Sto ancora lavorando su un approccio dinamico fluente DomainInclude<Customer>.Include("Orders").Include("Friends")
  3. Avrà bisogno della creazione di alcuni mapping "Ordini" = > "CustomerAccount.PayedOrders"

Framework hit IQueryable

I repository non espongono IQueryable, l'obiettivo è quello di nascondere il framework dell'entità. I datagrids di Devexpress necessitano di un IQueryable per consentire il paging / filtering senza caricare l'intera tabella in memoria.

Trovare una soluzione alternativa è quasi impossibile in quanto richiederebbe molto tempo e la portabilità della soluzione non è garantita con i nuovi rilasci di devexpress.

La mia domanda qui è: è un grosso problema permettere a devexpress di passare attraverso i livelli fino alla classe di contesto EF. Devo invece abbandonare Devexpress e usare un datagrids più flessibile (SJSha ExtJs, ...)

    
posta Jeremy D 22.11.2012 - 06:38
fonte

1 risposta

1

Hai una serie di domande nella tua domanda generale. Proverò a toccare ciascuno di essi.

Nel complesso, la risposta è:

"Sì, stai facendo le cose bene".

Raramente viene data un'architettura pulita e ideale da cui lavorare. Diamine, raramente ci viene data un'architettura, periodo. Piccola consolazione, me ne rendo conto. Ma stai facendo le domande giuste e prendendo l'approccio giusto.

Una cosa che potresti non aver realizzato è che isolare il layer EF e l'accesso al database è un passo verso l'incapsulamento delle modifiche che l'applicazione sta vedendo. Juval Lowy di iDesign è un grande sostenitore dell'incapsulamento del cambiamento . Il cambiamento è positivo perché ci tiene al lavoro e mantiene vive le nostre applicazioni, ma vogliamo limitare l'impatto che ogni cambiamento può avere sul resto dell'applicazione. Quindi lo incapsuliamo.

Non puoi abbassare la volatilità del tuo dominio (nota, non ho detto modello di dominio ) e non vorrai neanche se tu potessi. Tutto quello che puoi fare è racchiudere quella volatilità. Una volta che hai isolato la volatilità del tuo dominio, il tuo modello di dominio sarà allineato.

Identifica le aree del tuo database che sembrano soggette a cambiamenti più frequenti. Isolate questi aspetti in modo da poter apportare più facilmente le modifiche riducendo al minimo l'impatto a valle. L'utilizzo di un livello di accesso ai dati è un buon inizio. Potrebbe essere il momento di prendere in considerazione un sottolivello per l'accesso ai dati che ti permetta di creare un composto di quelli per il livello DA principale.

Alcune persone amano EF, alcune persone non vedono davvero molto vantaggio quando sono confrontate con i costi. Di quelli che usano EF, tendono a lavorare con l'ultima versione di quel set di strumenti. Gli aggiornamenti recenti (v4.5?) Hanno reso EF più utilizzabile / praticabile. Che sia o meno una buona decisione tecnologica per tu è qualcosa che solo tu puoi decidere. Guarda le tue alternative; esaminare il costo per passare a quelli; e andare avanti. Come suggerimento, crea un ramo di prova nel tuo repository, migra da EF su quel ramo e affronta alcune delle sfide. Allora lo saprai.

I problemi di prestazioni all'interno del database implicano che è necessario prendere in considerazione alcune ristrutturazioni. Normalizzazione , con moderazione, è una buona cosa. È facile esagerare con esso, ma ristrutturare le tabelle in modo che siano più facilmente indicizzate sarà probabilmente utile per i problemi di prestazioni. Questo potrebbe anche aiutare a incapsulare alcune delle modifiche che stai vedendo dagli aggiornamenti alle applicazioni.

Ad esempio, potresti avere una tabella CustomerInfo con una chiave primaria di CustomerID . Se App1 sta aggiungendo / modificando colonne ancillari su CustomerInfo , puoi dare a App1 il proprio sottotabella CustomerInfoExtensions reimpostato su CustomerInfo con CustomerID .

Non conosco alcun approccio di accesso ai dati che possa correggere la cattiva struttura all'interno delle tabelle del database. Quindi in questo caso si può "incolpare" EF quando il problema di root si trova nel DB. E non ci sono proiettili d'argento quando si tratta di scricchiolare enormi set di dati. Se DomainInclude<Customer>.Include("Orders").Include("Friends") crea un prodotto cartesiano attraverso le tue tabelle più grandi, beh, allora quella sarà semplicemente la tua query meno performante. Risolvi la query prima di preoccuparti del metodo di accesso ai dati.

L'esposizione di un IQueryable non è necessariamente una cosa negativa. Se hai bisogno (vuoi) di un'espressione più concreta di tale interfaccia, scegli un contenitore generico appropriato. Passiamo continuamente raccolte in tutto il mondo, e rende molto più semplice l'implementazione del pattern MVVM durante la visualizzazione dei dati . Penso che la tua preoccupazione qui sia che ritieni che dovrebbe esserci qualcosa di "di più" a ciò che sta tornando lo strato EF. Se un IQueryable è sufficiente, quindi usarne uno. Se è necessario un oggetto dati di prima classe sul reso, quindi crearne uno. Ma non creare un oggetto dati di prima classe solo per averne uno se IQueryable è abbastanza buono. Sarebbe un lavoro extra.

La domanda di DevExpress rispetto ad altri datagrids mi porta a una risposta di "meh". Hai delle sfide più grandi da risolvere prima di preoccuparti di quello. Considerare l'interfaccia utente (vista) come un'area che cambierà. Incapsulalo. Quando decidi di odiare FooBar-Grid (o qual è il tuo attuale gusto dell'interfaccia utente), puoi eliminarlo più facilmente. Personalmente, mi preoccuperei di migliorare innanzitutto il DB e i livelli di accesso ai dati, ma sono un ingegnere che apprezza la semplice eleganza della riga di comando. Chiamami di parte.

    
risposta data 28.11.2012 - 13:59
fonte

Leggi altre domande sui tag