Entity Framework con grandi sistemi - come dividere i modelli?

49

Sto lavorando con un database SQL Server con oltre 1000 tabelle, altre poche centinaia di visualizzazioni e diverse migliaia di stored procedure. Stiamo cercando di iniziare a utilizzare Entity Framework per i nostri nuovi progetti e stiamo lavorando sulla nostra strategia per farlo. La cosa su cui sono impiccato è il modo migliore per dividere le tabelle in modelli diversi (EDMX o DbContext se prima andiamo al codice). Posso pensare a qualche strategia a prima vista:

  • Dividi per schema
    Abbiamo le nostre tabelle divise in una dozzina di schemi. Potremmo fare un modello per schema. Questo non è perfetto, però, perché dbo continua a essere molto grande, con oltre 500 tabelle / viste. Un altro problema è che alcune unità di lavoro finiranno per dover fare transazioni che si estendono su più modelli, il che si aggiunge alla complessità, anche se presumo che EF lo renda abbastanza semplice.
  • Dividi per intento
    Invece di preoccuparsi degli schemi, dividi i modelli per intento. Quindi avremo modelli diversi per ogni applicazione, progetto, modulo o schermo, a seconda di quanto granulare vogliamo ottenere. Il problema che vedo con questo è che ci sono alcune tabelle che devono inevitabilmente essere utilizzate in ogni caso, come User o AuditHistory. Li aggiungiamo a tutti i modelli (viola DRY credo), o sono quelli in un modello separato che viene utilizzato da ogni progetto?
  • Non dividere affatto - un modello gigante
    Questo è ovviamente semplice da una prospettiva di sviluppo, ma dalla mia ricerca e dalla mia intuizione sembra che potrebbe comportarsi in modo terribile, sia in fase di progettazione, sia in fase di compilazione, sia in termini di tempo di esecuzione.

Qual è la migliore pratica per usare EF contro un database così grande? In particolare quali strategie usano le persone nella progettazione di modelli contro questo volume di oggetti DB? Ci sono opzioni che non sto pensando a quel lavoro meglio di quello che ho sopra?

Inoltre, questo è un problema in altri ORM come NHibernate? Se sì hanno trovato soluzioni migliori di EF?

    
posta RationalGeek 07.09.2012 - 22:18
fonte

4 risposte

30

Personalmente, ho provato a creare uno schema enorme per tutte le mie entità su un progetto abbastanza complesso ma piccolo (~ 300 tabelle). Abbiamo avuto un database estremamente normalizzato (5 ° normalizzazione del modulo (lo dico in modo approssimativo)) con molte relazioni "da molti a molti" e l'applicazione dell'integrità referenziale estrema.

Abbiamo anche usato una strategia "istanza singola per richiesta" che non sono nemmeno convinto di aver aiutato.

Quando si eseguono annunci semplici, ragionevolmente definiti "esplicitamente definiti", ricerche e salvataggi le prestazioni sono generalmente accettabili. Ma quando abbiamo iniziato a scavare in relazioni profonde, la performance sembrava prendere drastici tuffi. Rispetto ad un proc memorizzato in questo caso, non c'era confronto (ovviamente). Sono sicuro che avremmo potuto ottimizzare il codice base qui e là per migliorare le prestazioni, tuttavia, in questo caso, avevamo solo bisogno di un incremento delle prestazioni senza analisi a causa dei limiti di tempo e siamo tornati al processo memorizzato (lo abbiamo mappato ancora tramite EF, poiché EF forniva risultati strongmente tipizzati), ne avevamo solo bisogno come ripiego in alcune aree. Quando abbiamo dovuto attraversare tutto il database per creare una collezione (usando .include () senza risparmiarsi), la performance era notevolmente degradante, ma forse ci stavamo chiedendo troppo ...

Pertanto, in base alla mia esperienza, consiglierei di creare un .edmx per intento separato. Genera solo ciò che utilizzerai in base alla portata di tale esigenza. Potresti avere alcuni file .edmx con scope più piccoli per le attività finalizzate, e poi alcuni di grandi dimensioni in cui devi attraversare relazioni complesse per costruire oggetti. Non sono sicuro di dove sia questo punto magico, ma sono sicuro che ce n'è uno ... lol ...

Onestamente, a parte qualche insidia che abbiamo visto arrivare (complessa traversata), l'enorme .edmx ha funzionato bene da una prospettiva "lavorativa". Ma dovrai fare attenzione alla magia "fixup" che il contesto fa dietro la scena se non la disabiliti esplicitamente. Oltre a tenere sincronizzato .edmx quando vengono apportate modifiche al database, a volte è stato più facile cancellare l'intera superficie e ricreare le entità, che richiedevano circa 3 minuti, quindi non era un grosso problema.

Questo era tutto con EntityFramework 4.1. Sarei davvero interessato a conoscere anche la tua scelta ed esperienza finale.

E a proposito della tua domanda su nHibernate, questa è una lattina di domande sui vermi secondo me, ti farai abbaiare da entrambi i lati della recinzione ... Ho sentito un sacco di persone colpire EF per il gusto di colpire senza lavorando attraverso le sfide e comprendendo le sfumature esclusive di EF stesso .. e anche se non ho mai usato nHibernate in produzione, generalmente, se devi creare manualmente ed esplicitamente cose come i mapping, otterrai un controllo più preciso, tuttavia , se puoi trascinare e rilasciare, generare e avviare CRUD e interrogare usando LINQ, potrei dare una schifezza sulla granularità.

Spero che questo aiuti.

    
risposta data 07.09.2012 - 22:41
fonte
12

Vorrei iniziare con un semplice chiarimento: non ho esperienza con un database così grande, quindi il resto della mia risposta non si basa sull'esempio del mondo reale.

Quindi hai un database GRANDE e vuoi usarlo con ORM / EF. Vorrei andare con la seconda scelta. Ecco la mia spiegazione semplice per cui:

  • Il mapping aggiunge complessità. Non è necessario aggiungere complessità alle entità che la tua applicazione / progetto / modulo attuale non ha mai bisogno, ma non rendono la granularità troppo bassa. Non ti sarà di aiuto disporre di un set di mappatura separato per schermo.
  • Vuoi raggiungere l'unità di lavoro. Dovresti essere in grado di specificare quali tabelle richiede il modulo nella maggior parte dei casi (non è necessario in tutti i casi). Se metti queste tabelle in un unico set di mappatura sarai in grado di gestire la lettura e la modifica dei dati da un'unica istanza di contesto: questo è quello che dovrebbe essere il tuo obiettivo finale.
  • Non sono sicuro di cosa intendi per modello, ma anche con insiemi di mappature diversi puoi condividere classi tra insiemi di mappature usando gli stessi tipi di entità. Quindi se usi la tabella Utente in due moduli non hai bisogno di due classi Utente per rappresentare lo stesso. Puoi ancora usare una tabella singola e in caso di mappatura del codice (alias code-first) puoi anche definire una mappatura una volta e caricarla su più set di mappatura in modo che il principio DRY non venga violato, ma l'approccio code-first ha più limitazioni quando arriva a viste e stored procedure. EDMX rende questo più difficile. Puoi ancora riutilizzare le classi ma riutilizzare la mappatura impossibile.
  • E le interrogazioni sui moduli incrociati? Queste domande possono accadere, ma per essere onesti non tutto deve essere gestito da EF. È possibile sfruttare l'EF per i casi più comuni per semplificare l'accesso regolare ai dati, ma se si ha bisogno di una query speciale che unisce le tabelle appartenenti a 5 moduli diversi, è sufficiente eseguirlo direttamente o avvolgerlo nella stored procedure. La sostituzione al 100% dell'accesso ai dati nativi può essere difficile, complessa e controproducente.
  • L'ultimo punto è semplicemente pratico: non credo che gli strumenti VS siano pronti per lavorare con un insieme così grande di oggetti - non nel designer, nemmeno con lo strumento di importazione. Lavoravo su un database molto grande con accesso ai dati tradizionale e progetto Database SQL in VS2008 - l'esperienza utente con un progetto complesso era pessima. È necessario mantenere basso il numero di tabelle utilizzate - il cap per designer deve essere compreso tra 100-200 ma anche 100 tabelle gestite da un singolo contesto (insieme di mappature) suona come una responsabilità eccessiva per una classe (supponiamo che avrete 100 proprietà set esposto nel contesto - non sembra un buon design).
risposta data 07.09.2012 - 23:40
fonte
3

Direi che non puoi decidere questo tipo di domande da un punto di vista tecnico. Ti consiglio di costruire la tua architettura in base ai tuoi casi d'uso (storie degli utenti, ecc.). Prima trova i tuoi oggetti di business. Un oggetto entità non è per impostazione predefinita un oggetto business. Tipico si avrà un oggetto business davanti agli oggetti entità. Quindi puoi decidere in modo incrementale ciò di cui hai veramente bisogno, in base ai requisiti dell'utente.

"Un buon architetto massimizza il numero di decisioni non prese". Robert C. Martin

link

    
risposta data 10.09.2012 - 20:40
fonte
2

Uso un approccio ibrido: gli elementi OLTP sono gestiti da EF mentre operazioni pesanti come inserimenti batch, aggiornamenti di massa, query di report, ecc. sono gestiti da Stored Proc. Rende anche il percorso di migrazione più facile se non stai facendo una riscrittura completa del tuo livello dati tutto in una volta.

    
risposta data 11.09.2012 - 21:23
fonte

Leggi altre domande sui tag