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.
Ilmiomodellodidominioèaltamentevolatile,continuaaevolversiconleappinseguitoall'aumentodeinuovicampi.Lacomplessitàdiessocontinuaacrescereelaclasseincuiessacontieneiniziaaotteneremolteproprietà.
CreareunastrategiadiinclusioneeriproiettaresuEFèmoltocomplicato(imieioggettididominiononhannoalcuntipodiproprietàdirapportodicaricamentopigro/ansioso):
DomainInclude<Domain.Model.Bar>.Include("Customers").Include("Customers.Friends") // To... IFooContext.Bars.Include(...).Include(...).Where(...)
-
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);
- Otterrai risultati nella classe di servizio contenente migliaia di GetCustomersWith ... With ...
- Creerà molta classe ereditata da IncludeStrategy. Sto ancora lavorando su un approccio dinamico fluente
DomainInclude<Customer>.Include("Orders").Include("Friends")
- 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, ...)