2014-06-19 9 views
5

Ho 2 diverse unità di lavoro: una basata su ADO.NET , chiamando le stored procedure per lo più (uowADO) e un altro con Entity Framework 6 (uowEF), aggiunto di recente al fine di sostenere Oracle db, in modo che non debba riscrivere tutti gli SP (la mia conoscenza è limitata lì).Come progettare l'unità di lavoro per supportare le operazioni di carico e fornire maggiori prestazioni?

Quindi, strato di business sta caricando solo uno di loro (in base alla configurazione) durante l'esecuzione di operazioni su database (ma io non li posso usare in parallelo, perché uowADO non supporta Oracle)

Dopo aver aggiunto il nuovo uowEF Ho notato grandi problemi di prestazioni, ovviamente principalmente sulle operazioni di massa.

Fondamentalmente ho solo Commit e Rollback metodi sulla corrente IUnitOfWork per ora ... molto vicino a ciò che questo article raccomanda.

Quindi, sto pensando di rielaborare questa unità di lavoro. Ad esempio, ho letto sulla disattivazione di dbContext.Configuration.AutoDetectChangesEnabled a volte quando sono coinvolte operazioni di massa e altri suggerimenti di ottimizzazione relativi a EF che possono essere di aiuto.

Purtroppo io non sono sicuro di come progettare tale unità di lavoro per renderlo generico in modo che ho potuto usarlo in tutti i casi da BL e per entrambi i livelli di accesso ai dati: ADO.NET e EF.

Qualche idea, consigli, buoni collegamenti su questo?

+0

Pattern di eventi del dominio, consistenza finale. Ma non è facile se non hai familiarità con le architetture DDD ed event driven – MikeSW

risposta

1

Non c'è una risposta chiara.È sempre il compromesso tra flessibilità e prestazioni. Tutti questi modelli (repository, unità di lavoro) sono buoni per flessibilità, ma non per prestazioni poiché le implementazioni concrete richiedono di solito alcune modifiche per fornire le massime prestazioni e queste modifiche potrebbero non essere compatibili con l'interfaccia generica. È possibile adattare l'interfaccia, ma potrebbe non funzionare con altre implementazioni. Tutti questi ORM sono molto diversi e molto difficile (quasi impossibile) implementare l'interfaccia generica di repository/UOF per supportarli tutti, specialmente se si dispone di ADO (ORM di basso livello, in realtà è difficile chiamarlo ORM) e EF (ORM di alto livello). L'impostazione di AutoDetectChangesEnabled su false è solo una piccola parte di ciò che puoi fare con EF. Per ottenere maggiori prestazioni da esso, devi anche implementare le entità in un modo specifico (aggiungi alcune proprietà, alcuni attributi). Se osserviamo Linq2Sql (un altro ORM), richiede query compilati, quindi, dimenticare metodi come questo:

T Single(Expression<Func<T, bool>> predicate); 

nei repository. E sto solo parlando di repository per database relazionali. Che dire dei repository per i database NoSql? Che dire dei repository basati su fonti di dati completamente diverse? Sì, è possibile fornire un'interfaccia generica con logica generica, ma sarebbe molto lenta per alcune fonti di dati. Se davvero si vuole implementare soluzione generica e ottenere la massima performance, i repository per UOF dovrebbero avere un'interfaccia molto specifico come:

IEnumerable<T> GetStudentsByName(srting name) 

void InsertStudents<T>(IEnumerable<T> students) 

dove T - entità di livello aziendale che non dovrebbe dipendere sull'attuazione concreta repository. I repository dovrebbero essere responsabili della conversione della T in entità accettabili per ORM che implementa l'accesso. Ma tieni a mente che la soluzione sarà troppo complessa e difficile da sopportare.

Se fossi in te, sceglierei un ORM principale che meglio si adatta alle mie esigenze e progetterei repository attorno a questo ORM per ottenere il massimo delle prestazioni da esso. Ma terrò l'interfaccia abbastanza flessibile da avere la possibilità di implementare almeno l'accesso lento (ma funzionante) ad altre sorgenti di dati o ORM.

+0

Finalmente qualche input che conferma i miei pensieri ... grazie! Pensavo di prendere tutto sbagliato, perché è davvero difficile trovare una buona soluzione. Hai perfettamente ragione, ho effettivamente implementato tutto come suggerivi anche tu. Quindi, per ora, ho solo una soluzione che funziona per entrambi, ADO ed EF, ma con un EF lento ... e anche un mappatore con cache aggiuntiva tra il mio dominio e le entità EF. Almeno ora so che non sono lontano. – Learner

1

Purtroppo io non sono sicuro di come progettare tale unità di lavoro per renderlo generico in modo che io possa usarlo in tutti i casi da BL e per entrambi i dati strati di accesso: ADO.NET e EF.

iniziare realizzando che EF ha modo di accedere al database. Si affida a ADO.NET per questo. Alla fine, usa comandi, datareader ecc. Per fare il lavoro di basso livello.

È banale impostare le cose in modo che sia possibile estrarre la connessione in un contesto EF e quindi utilizzare direttamente ADO.NET.

Dato che EF non ha alcun supporto per eseguire operazioni di volume efficiente anche con volumi ridotti, è comunque possibile/dover fare affidamento su ADO.NET. EF stesso è un perfetto esempio di anti-esempio da un punto di vista SQL su come gestire il database per volumi più grandi. Si tratta di un aggiornamento/inserimento per riga, anche se (anche ignorando SqlBulkCopy per esempio) potrebbe per la maggior parte dei database emettere uno per più righe, poiché la sintassi lo consente perfettamente.

Come richiesto: Raggiungere la connessione sottostante è davvero banale quando ti piace leggere la documentazione dei campioni. Questo è il codice che uso per gli inserimenti di massa. La classe ObjectBulkCopy è un po 'più complesso, ma qui si può vedere come ottenere la connessione al database:

public static void BulkInsert<T>(this Repository repository, IEnumerable<T> objects) where T : class 
     { 
      var bulkCopy = new ObjectBulkCopy<T>(); 
      var connection = (SqlConnection) repository.Database.Connection; 
      bulkCopy.Insert (objects, connection); 
     } 

Scherzi banale - è lì in qualsiasi repository come una proprietà, pronto per la colata.

+0

Stai dicendo di "usare direttamente ADO.NET" ... non sono sicuro di vedere in che modo chiaro come ... potresti mostrarmi qualche pseudo- codice? Forse dovrei anche avere qualche pseudo-codice nella mia domanda per mostrare quello che ho finora. – Learner

+0

Non è necessario lo pseudocodice. Tutto ciò di cui hai bisogno è la connessione .... e questo è facilmente disponibile. Aggiungere codice – TomTom

+0

So come ottenere la connessione, ma non ho capito come volevi averlo. Ora vedo che stai usando un metodo "BulkInsert" per i repository. In realtà ho solo una funzione "Inserisci" nel repository. Se voglio eseguire più inserimenti, apro una transazione sql e utilizzo un ciclo da BL. – Learner

Problemi correlati