c# configuration - Entity Framework Complex Type vs Creating new Entity




fluent api (4)

Questa domanda è già da un po 'di tempo, ma aggiungerò comunque una risposta nella speranza che il prossimo povero singhiozzo che arriva sappia di cosa si tratta.

I tipi complessi non supportano il caricamento lazy, almeno non in EF 4.3. Prendiamo come esempio la situazione dell'indirizzo. Hai una tabella Persona con 15 colonne, 5 delle quali contengono informazioni sull'indirizzo per determinati individui. Ha 50k record. Si crea entità Persona per la tabella con un indirizzo di tipo complesso.

Se hai bisogno di un elenco di nomi di tutti gli individui nel tuo database, dovresti farlo

var records = context.Persons;

che include anche indirizzi, che pompano valori di 5 * 50k nella tua lista senza motivo e con notevole ritardo. Puoi scegliere di caricare solo i valori di cui hai bisogno in un tipo anonimo con

var records = from p in context.Persons
              select new {
                LastName = p.LastName,
                FirstName = p.FirstName,
              }

che funziona bene per questo caso, ma se avessi bisogno di un elenco più completo con, per esempio, 8 colonne senza indirizzo, dovresti aggiungere ognuna di esse nel tipo anonimo o semplicemente andare con il primo caso e tornare al caricamento dell'indirizzo inutile dati.

Ecco la cosa sui tipi anonimi: sebbene siano molto utili all'interno di un singolo metodo, ti costringono a usare variabili dinamiche altrove nei tuoi bambini di classe o classe, che annullano alcune delle strutture di refactoring di Visual Studio e ti lasciano aperti agli errori di runtime. Idealmente, vuoi far circolare le entità tra i tuoi metodi, quindi quelle entità dovrebbero trasportare il bagaglio più piccolo possibile. Questo è il motivo per cui il caricamento lento è così importante.

Quando si giunge all'esempio sopra, le informazioni sull'indirizzo dovrebbero essere in una tabella a sé stante con un'entità completa che la copre. Come vantaggio collaterale, se il cliente richiede un secondo indirizzo per una persona, è possibile aggiungerlo al modello semplicemente aggiungendo un riferimento indirizzo aggiuntivo in Persona.

Se diversamente dall'esempio precedente hai effettivamente bisogno dei dati dell'indirizzo in quasi tutte le query che fai e vuoi veramente avere quei campi nella tabella Persona, quindi aggiungili semplicemente all'entità Person. Non avrai più il prefisso Address, ma non è esattamente qualcosa per cui perdere il sonno.

Ma aspetta, c'è dell'altro!

I tipi complessi sono un caso speciale, un urto sul paesaggio regolare di entità EF semplici. Quelli del tuo progetto potrebbero non essere idonei ad ereditare dalla tua classe base dell'entità, rendendo impossibile metterli attraverso i metodi che trattano con le tue entità in generale.

Supponiamo che tu abbia una classe di base entità chiamata EntityModel che definisce un ID di proprietà. Questa è la chiave per tutti gli oggetti di entità, quindi ora puoi creare

class EntityModelComparer<T> : IEqualityComparer<T> where T : EntityModel

che puoi quindi utilizzare con Distinct () per filtrare i duplicati da qualsiasi IQueryable di tipo T in cui T è una classe di entità. Un tipo complesso non può ereditare da EntityModel perché non ha una proprietà ID, ma va bene perché comunque non lo si utilizzerà in modo distinto.

Più avanti ti imbatti in una situazione in cui hai bisogno di un modo per passare attraverso qualsiasi entità ed eseguire un'operazione. Forse si desidera elencare dinamicamente le proprietà di un'entità nell'interfaccia utente e consentire all'utente di eseguire query su di esse. Quindi costruisci una classe che puoi istanziare per un particolare tipo e far sì che si occupi di tutto:

public class GenericModelFilter<T> : where T : EntityModel

Oh aspetta, il tuo tipo complesso non è di tipo EntityModel. Ora è necessario complicare l'albero di ereditarietà delle entità per adattarsi a tipi complessi o eliminare il contratto EntityModel e ridurre la visibilità.

Andando avanti, si aggiunge un metodo alla classe che in base alle selezioni dell'utente può creare un'espressione che è possibile utilizzare con linq per filtrare qualsiasi classe di entità

Expression<Func<T, bool>> GetPredicate() { ... }

quindi ora puoi fare qualcosa del genere:

personFilter = new GenericModelFilter<Person>();
companyFilter = new GenericModelFilter<Company>();
addressFilter = new GenericModelFilter<Address>(); //Complex type for Person

...

var query = from p in context.Persons.Where(personFilter.GetPredicate())
            join c in context.Companies.Where(companyFilter.GetPredicate()) on p.CompanyID = c.ID
            select p;

Funziona allo stesso modo per tutti gli oggetti entità ... eccetto Address con i suoi bisogni speciali. Non puoi fare un join per questo come hai fatto con Company. Puoi navigarci da Persona, ma come applichi quell'Espressione su di esso e alla fine finirai con la Persona? Ora devi prendere il momento e capire questo caso speciale per un sistema semplice che funziona facilmente ovunque.

Questo schema si ripete per tutta la durata di un progetto. Parlo per esperienza? Vorrei non averlo fatto. I tipi complessi continuano a fermare i tuoi progressi, come uno studente malintenzionato sul retro della classe, senza aggiungere nulla di essenziale. Fai un favore a te stesso e opta per oggetti di entità reali.

Sto leggendo su Entity Framework 4.0 e mi chiedevo perché dovrei creare un tipo complesso e non una nuova entità (tabella) e una relazione tra loro?


Basato su Domain Driven Design Concepts, la radice Aggregate potrebbe avere uno o più oggetti interni come parti. In questo caso, gli oggetti interni - all'interno del limite della radice di aggregazione - non hanno alcuna CHIAVE. La chiave madre verrà applicata a loro o in qualche modo come questo. La tua risposta ritorna al vantaggio di mantenere tutte le parti all'interno della radice Aggregate che rende il tuo modello più robusto e molto più semplice.


L'esempio perfetto è un indirizzo. L'utilizzo di un tipo complesso per un indirizzo è molto più facile da gestire rispetto a una nuova entità. Con tipi complessi non hai a che fare con la chiave primaria. Pensa all'accesso a un indirizzo quanti tipi comuni di entità avrebbero un indirizzo (unità aziendali, persone, luoghi). Immagina di popolare molti indirizzi di persone e di dover impostare una chiave per ognuno. Con tipi complessi è sufficiente accedere alle proprietà interne di loro tipo e il gioco è fatto. Ecco un link MSDN di un esempio. http://msdn.microsoft.com/en-us/library/bb738613.aspx


Ho trovato una risposta molto buona here che spiega quando usare ciò in parole semplici:

La regola di base per quale framework utilizzare è come pianificare la modifica dei dati nel livello di presentazione.

  • Linq-To-Sql : utilizzare questo framework se si intende modificare una relazione uno a uno dei dati nel livello di presentazione. Significa che non hai intenzione di combinare i dati di più di una tabella in una vista o pagina.

  • Entity Framework : utilizzare questo framework se si intende combinare i dati di più tabelle nella vista o nella pagina. Per renderlo più chiaro, i termini di cui sopra sono specifici per i dati che verranno manipolati nella vista o nella pagina, non solo visualizzati. Questo è importante da capire.

Con Entity Framework è possibile "unire" i dati presentati per presentare al livello di presentazione in un formato modificabile, e quindi quando tale modulo viene inviato, EF saprà come aggiornare TUTTI i dati dalle varie tabelle.

Ci sono probabilmente motivi più accurati per scegliere EF su L2S, ma questo probabilmente sarebbe il più facile da capire. L2S non ha la capacità di unire i dati per la presentazione della vista.







c# .net entity-framework .net-4.0