Entity Framework con sistemi di grandi dimensioni: come dividere i modelli?


50

Sto lavorando con un database SQL Server con oltre 1000 tabelle, altre 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 alla nostra strategia per farlo. La cosa a cui sono bloccato è il modo migliore di dividere le tabelle in diversi modelli (EDMX o DbContext se andiamo prima al codice). Posso pensare ad alcune strategie fin dall'inizio:

  • Dividi per schema
    Abbiamo le nostre tabelle divise probabilmente attraverso una dozzina di schemi. Potremmo fare un modello per schema. Questo non è perfetto, tuttavia, perché dbo finisce per 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 aumenta la complessità, anche se presumo che EF lo renda abbastanza semplice.
  • Dividi per intento
    Invece di preoccuparti degli schemi, dividi i modelli per intento. Quindi avremo modelli diversi per ogni applicazione, progetto, modulo o schermo, a seconda di quanto vogliamo ottenere. Il problema che vedo con questo è che ci sono alcune tabelle che inevitabilmente devono essere utilizzate in ogni caso, come Utente o AuditHistory. Aggiungiamo quelli a ogni modello (viola il DRY credo) o quelli in un modello separato che viene utilizzato da ogni progetto?
  • Non dividere affatto: un modello gigante
    Questo è ovviamente semplice dal punto di vista dello sviluppo, ma dalla mia ricerca e dalla mia intuizione sembra che potrebbe funzionare in modo terribile, sia in fase di progettazione, in fase di compilazione e possibilmente in fase di esecuzione.

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

Inoltre, questo è un problema in altri ORM come NHibernate? In tal caso, hanno trovato soluzioni migliori di EF?


"dover effettuare transazioni che si estendono su più modelli, il che aumenta la complessità" Solo una nota qui che sarà necessario abilitare Microsoft Distributed Transaction Coordinator. Una volta installato e funzionante, dovrebbe essere semplice realizzare ciò di cui parli.
Tjaart

@Tjaart grazie. Ho usato MS DTC prima e mentre è piuttosto semplice, aggiunge complessità oltre un semplice DB txn, quindi voglio evitarlo ogni volta che è possibile.
RationalGeek,

2
4 anni dopo, cosa hai deciso e cosa consiglieresti ora?
Rory,

Risposte:


31

Personalmente, ho provato a realizzare uno schema enorme per tutte le mie entità su un progetto abbastanza complesso ma piccolo (~ 300 tabelle). Avevamo un database estremamente normalizzato (normalizzazione di quinta forma (lo dico vagamente) con molte relazioni "da molte a molte" e un'applicazione estrema di integrità referenziale.

Abbiamo anche usato una strategia di "istanza singola per richiesta" che non sono convinto sia stata di aiuto.

Quando si eseguivano elenchi "esplicitamente definiti" semplici, ragionevolmente piatti, le ricerche e i salvataggi erano generalmente accettabili. Ma quando abbiamo iniziato a scavare in relazioni profonde, la performance sembrava subire drastici cali. Rispetto a un proc memorizzato in questo caso, non c'è stato confronto (ovviamente). Sono sicuro che avremmo potuto modificare la base di codice qua e là per migliorare le prestazioni, tuttavia, in questo caso avevamo solo bisogno di un aumento delle prestazioni senza analisi a causa di vincoli temporali e siamo tornati al proc memorizzato (ancora mappato tramite EF, poiché EF ha fornito risultati fortemente tipizzati), ne avevamo bisogno solo come ripiegamento in alcune aree. Quando abbiamo dovuto attraversare tutto il database per creare una raccolta (usando .include () in modo ineguagliabile), le prestazioni erano notevolmente degradanti, ma forse stavamo chiedendo troppo ...

Quindi, in base alla mia esperienza, consiglierei di creare un .edmx separato per intento. Genera solo ciò che utilizzerai in base all'ambito di tale esigenza. Potresti avere alcuni file .edmx con ambito più piccolo per attività finalizzate, e poi alcuni di grandi dimensioni in cui è necessario attraversare relazioni complesse per costruire oggetti. Non sono sicuro di dove si trovi quel punto magico, ma sono sicuro che ce n'è uno ... lol ...

Onestamente, a parte alcune insidie ​​che abbiamo visto arrivare (traversate complesse), l'enorme .edmx ha funzionato bene da una prospettiva "funzionante". Ma dovrai fare attenzione alla magia "fixup" che il contesto fa dietro la scena se non la disabiliti esplicitamente. Oltre a mantenere sincronizzato .edmx quando vengono apportate modifiche al database .. a volte era 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 la tua scelta e la tua esperienza.

E per quanto riguarda la tua domanda su nHibernate, questa è una lattina di vermi domanda secondo me, abbaierai su entrambi i lati della recinzione ... Sento un sacco di persone che colpiscono EF per il gusto di colpire senza lavorare attraverso sfide e comprensione delle sfumature uniche di EF stesso .. e sebbene non abbia mai usato nHibernate in produzione, in genere, se devi creare manualmente ed esplicitamente cose come i mapping, otterrai comunque un controllo più limitato se posso trascinare n 'drop, generare e avviare CRUD'ing e interrogare usando LINQ, potrei fregarmene di granularità.

Spero che questo possa essere d'aiuto.


1
Cordiali saluti - Esiste un'utilità di mappatura NHibernate che rende queste mappature MOLTO facili e automatizzate.
Ganders,

@ganders - Ha un'interfaccia utente e come è l'integrazione IDE? Suppongo che lo punti a un'origine dati e rispetti l'integrità referenziale e l'attraversamento degli oggetti e crei gli oggetti di mappatura?
hanzolo,

1
Sì sì (GUI). Finora non ho avuto problemi. Utilizzato su 4 o 5 diversi progetti / siti Web. Nota: lo uso con Fluent NHibernate, che esegue la mappatura nel codice c #, non nei file config / xml. Ecco un link: nmg.codeplex.com
paperi

13

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 BIG e vuoi usarlo con ORM / EF. Vorrei andare con la seconda scelta. Ecco la mia semplice spiegazione del perché:

  • La mappatura aggiunge complessità. Non è necessario aggiungere complessità alle entità di cui l'applicazione / progetto / modulo attuale non necessitano mai, ma non rendono la granularità di livello troppo basso. Avere una mappatura separata impostata per schermo non ti aiuterà.
  • Vuoi raggiungere l'unità di lavoro. Dovresti essere in grado di specificare quali moduli delle tabelle hanno bisogno nella maggior parte dei casi (non necessario in tutti i casi). Se metti queste tabelle in un unico set di mappature sarai in grado di gestire la lettura e la modifica dei dati per singola istanza di contesto - questo è quello che dovrebbe essere il tuo obiettivo finale.
  • Non sono sicuro di cosa significhi esattamente per modello, ma anche con diversi set di mapping è possibile condividere classi tra set di mapping utilizzando gli stessi tipi di entità. Pertanto, se si utilizza la tabella utente in due moduli, non sono necessarie due classi utente per rappresentare la stessa. Puoi ancora usare una singola tabella e in caso di mappatura del codice (aka code-first) puoi persino definire una volta la mappatura e caricarla su più set di mappature in modo che il principio DRY non venga violato ma l'approccio code-first ha più limitazioni quando arriva alle visualizzazioni e alle stored procedure. EDMX rende questo più difficile. Puoi ancora riutilizzare le classi ma riutilizzare il mapping impossibile.
  • Che dire delle domande tra i moduli? Queste domande possono accadere, ma a dire il vero non tutto deve essere gestito da EF. Puoi sfruttare EF in casi comuni per semplificare l'accesso regolare ai dati ma se hai bisogno di un posto per una query speciale che unisce le tabelle appartenenti a 5 moduli diversi, puoi semplicemente eseguirlo direttamente o avvolgerlo nella procedura memorizzata. 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 a lavorare con un così ampio insieme di oggetti - non in designer, nemmeno con strumenti di importazione. Lavoravo su un database molto grande con un accesso tradizionale ai dati e un progetto di database SQL in VS2008: l'esperienza utente con un progetto complesso era pessima. Devi mantenere basso il numero di tabelle utilizzate: il limite per designer dovrebbe essere compreso tra 100-200 ma anche 100 tabelle gestite da un singolo contesto (set di mapping) sembrano troppe responsabilità per una classe (supponiamo che tu abbia 100 proprietà set esposto sul contesto - non sembra un buon design).

4

Direi che non puoi decidere questo tipo di domanda dal punto di vista tecnico. Ti consiglierei di costruire la tua architettura in base ai tuoi casi d'uso (user story, ecc.). Per prima cosa trova i tuoi oggetti business. Un oggetto entità non è per impostazione predefinita un oggetto business. Tipicamente 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

http://cleancoder.posterous.com/architecture-deference


3

Uso un approccio ibrido: le cose OLTP sono gestite da EF mentre le operazioni pesanti come inserimenti batch, aggiornamenti di massa, richieste di rapporti, ecc. Sono gestite da Stored Procs. Inoltre, semplifica il percorso di migrazione se non stai eseguendo una riscrittura completa del tuo livello di dati contemporaneamente.


Sembra una buona strategia, ma in realtà non affronta la questione di come dividere le entità tra diversi modelli EF. Hai tutte le entità in un modello o dividi e vinci in qualche modo?
RationalGeek,

1
Se le prestazioni OLTP sono sufficienti con l'approccio full-model, procedere con quello. Puoi sempre romperlo in seguito, se necessario, ma il modo più rapido e agile è caricare tutto. Potresti non aver mai bisogno dei miglioramenti delle prestazioni che ottieni rompendola, quindi perdi tempo e rendi il tuo sistema più complicato senza motivo. Quindi c'è la domanda su quale modello si attaccherebbe una nuova tabella / entità quando si decide di espandersi. E cosa succede quando è necessario eseguire un aggiornamento su più modelli. Salva te stesso il mal di testa a meno che tu non abbia davvero un'alternativa.
Nik,

Hai dimenticato di dire che puoi sempre modificare le tue prestazioni quando accedi ai tuoi dati. Guarda le opzioni di caricamento pigro / desideroso e quali entità figlio stai introducendo. Non vedo alcun motivo per cui un modello completo si comporterebbe peggio di un modello più piccolo se non si caricano alberi di oggetti di grandi dimensioni.
Nik,

direi che enormi alberi di oggetti e una struttura di dati normalizzata vanno di pari passo quando si tratta di schemi di grandi dimensioni
hanzolo,

Sei tu a controllare quanto poco o quanto vuoi saturare il grafico degli oggetti.
Nik,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.