Entity Framework Code Prima, classe C # separazione ed EAV

1

Sto riprogettando una parte della mia applicazione ASP.NET MVC. Attualmente sto utilizzando il primo approccio al codice Entity Framework 6.1.

Recentemente ho letto che (correggimi se sbaglio, non ne so molto di DB): i join sono costosi; dovremmo mantenere il nostro database normalizzato e con il minor numero possibile di query eseguite. Entity Framework fa un join ogni volta che "virtuale" una proprietà e proviamo a recuperarla (Eager / Lazy Loading). Dovremmo evitare un approccio di Entity-Attribute-Value (EAV), a meno che la denormalizzazione non sia desiderabile (correggimi).

Codice Il primo approccio ci consente di scrivere lo schema DB usando il codice COP OO (POCO). Il che significa che dovremmo aderire ai principi SOLID di OOP (correggimi). Il primo è Single Responsibility, il che significa che una classe dovrebbe fare solo una cosa (di nuovo, correggimi se sbaglio).

Ora arriva il problema (questa è la prima volta che succede a me). Ho una classe con circa 30 proprietà. Prima di pensare all'anti-EAV, sono andato a separare il modello di conseguenza:

Come puoi vedere, ho molte proprietà virtuali senza la Lista < > tipo, questo significa che si tratta di una relazione uno-a-uno. Ho letto in un precedente post di overflow dello stack che una buona regola empirica è che le relazioni one-to-one dovrebbero essere evitate a favore di averle in una stessa tabella. Questo è, naturalmente, se quell'uno contro uno non viene chiamato da altre tabelle. Impediamo EAV e quindi, Joins.

Seguendo i principi SOLID, ho estrapolato alcune proprietà a classi esterne. Avranno il loro tavolo.

Quindi, la domanda sarà: dovrei favorire una progettazione completamente normalizzata rispetto a un approccio OOP durante la modellazione in Entity Framework?

    
posta Jose A 15.04.2016 - 18:22
fonte

2 risposte

4

(In ritardo alla festa, ma non ho potuto resistere)

Risolviamo alcuni malintesi.

Joins are expensive

Rispetto a cosa? Ovviamente, leggere un tavolo piatto è "più economico" di unire tabelle, ma qualsiasi RDBMS maturo è altamente ottimizzato per l'esecuzione di join perché sono inevitabilmente parte di progetti di database validi. I vincoli sui vincoli di chiave esterna (i più comuni) sono particolarmente ottimizzati. E, naturalmente, l'indicizzazione corretta è indispensabile.

we should keep our database normalized and with the least queries executed as possible

Il modo in cui lo poni, sembra essere una conseguenza di impedire questi "costosi" join. Il contrario è vero. La normalizzazione genererà sempre più tabelle e, quindi, più join per interrogare gli stessi dati di uno schema di dati denormalizzato. (Beh, per essere onesti con te, in seguito dici "Preveniamo EAV e quindi, Joins.").

We should avoid an Entity-Attribute-Value approach (EAV), unless denormalization becomes desirable

L'EAV è quasi una denormalizzazione. Ho l'impressione che tu non comprenda appieno cos'è l'EAV.

In un progetto EAV, attributi di una relazione (ovvero campi o colonne , di una tabella del database ) sono presi da una relazione e memorizzati come record in una tabella Attributi. I valori sono memorizzati in un'altra tabella con chiavi esterne alla tabella Attributi e una tabella Entità . Un record nelle tabelle Attributi esprime un fatto: questo è il valore X dell'attributo Y nell'entità Z.

Quindi con EAV, se applicato con rigore, se vuoi conoscere la data di inizio, la data di fine e il costo di un torneo, dovrai eseguire una query sulla tabella PGTournament e unirti a Attributo e Valore (con WHERE condizione per gli attributi). Si tratta di due join anziché zero senza EAV!

Quasi sempre, l'EAV è un cattivo design. Va usato quando non ci sono alternative (ad esempio nelle applicazioni di laboratorio in cui nuove analisi per campioni possono essere inventate ogni giorno - un set fisso di campi in una tabella di esempio non è sufficiente).

Nel tuo caso, non vedo alcun motivo per introdurre l'EAV: non capisco nemmeno perché lo fai crescere. Penso che sia perché confondi EAV con le associazioni 1: 1. Continua a leggere.

Which means that we should adhere to OOP's SOLID Principles

Il modello di classe EF fa parte di un livello di accesso ai dati . Non è un modello di dominio! Almeno, non è la sua prima responsabilità ad esserlo. Le proprietà della classe dovrebbero facilitare l'accesso ai dati. Ciò significa che ci saranno relazioni bidirezionali e proprietà di identificazione, per menzionare due anti-pattern OOP. E il vero bummer OOP: le classi tendono ad essere altamente anemiche. Ogni volta che le classi EF possono essere utilizzate come classi di dominio, questo è un semplice bonus .

virtual properties without the List<> type

Tali proprietà sono note come proprietà di navigazione perché "navigano" verso altre entità. Gli elenchi sono proprietà di navigazione della raccolta e le proprietà del tipo di entità (senza il tipo List<> ) sono proprietà di navigazione di riferimento . Non devono essere virtuali. Quando sono virtuali, EF potrebbe essere in grado di caricare pigramente le proprietà.

this means that it is a one-to-one relationship

Perché? Le proprietà di navigazione di riferimento sono spesso la parte "1" di un'associazione 1: n. Penso che la maggior parte delle tue proprietà di riferimento siano così. Ad esempio, GameGenre . Penso che ci siano molti tornei con lo stesso GameGenre . È un'associazione 1 (genere) a n (torneo), anche se GameGenre non ha una raccolta Tournaments . Forse solo TournamentSettings e MainImage sono associazioni 1: 1 effettive.

Le associazioni 1: 1 distribuiscono i dati appartenenti a un'entità su più tabelle. Ci possono essere ottime ragioni per farlo. Uno di questi è facilitare l'interrogazione di dati leggeri senza il pesante carico utile di qualche blob, come MainImage . Un altro separa i dati sensibili dai dati pubblici. O dati comuni (spesso interrogati) da dati specializzati (a volte interrogati), forse il tuo TournamentSettings .

Ora, finalmente, la tua domanda:

should I favor a fully normalized design over a OOP Approach when modeling in Entity Framework?

Stai confrontando mele e arance. La progettazione normalizzata è database, OOP è un modello di classe. Ma se c'è qualcosa da favorire, è il design normalizzato. Una progettazione di database ben strutturata è fondamentale per qualsiasi applicazione basata su dati. Tutto il resto segue. Il modello di classe EF necessariamente rifletterà strettamente la struttura del database. Come ho detto sopra: deve essere visto come un livello di accesso ai dati.

Ma ogni volta che modellate la logica di business, ovviamente, provate a farlo nel modo più SOLIDO possibile. Ciò significa che a volte dovrai compilare un modello di dominio specializzato dalle entità interrogate da EF e, a volte, le classi EF possono essere estese per incapsulare comportamenti e dati (che è tutto ciò che riguarda OOP).

    
risposta data 12.08.2016 - 00:47
fonte
1

Erg, questo è il motivo per cui odio EF.

I join non sono costosi se indicizzi

Le proprietà non elenco non sono sempre le relazioni 1-1, ma possono anche essere molte a uno.

La normalizzazione del database è davvero buona se hai bisogno di guardare il tuo database. (così come gli altri motivi per cui è buono) EF può creare e leggere un DB "difficile per gli umani"

Preferibilmente per un bel db leggibile e flessibile vuoi una tabella per classe con una chiave primaria. Relazioni rappresentate da chiavi esterne o unendo molte a molte tabelle non classificate

    
risposta data 16.04.2016 - 08:02
fonte

Leggi altre domande sui tag