Primo codice: associazioni indipendenti e associazioni chiave estere?

Ho un dibattito mentale con me stesso ogni volta che inizio a lavorare su un nuovo progetto e sto progettando i miei POCO. Ho visto molti tutorial / esempi di codice che sembrano favorire le associazioni di chiavi estranee :

Associazione chiave esterna

public class Order { public int ID { get; set; } public int CustomerID { get; set; } // <-- Customer ID ... } 

Al contrario delle associazioni indipendenti :

Associazione indipendente

 public class Order { public int ID { get; set; } public Customer Customer { get; set; } // <-- Customer object ... } 

Ho lavorato con NHibernate in passato e ho utilizzato associazioni indipendenti, che non solo sentono più OO, ma anche (con caricamento lento) hanno il vantaggio di darmi accesso all’intero object Cliente, anziché solo il suo ID. Ciò mi consente, ad esempio, di recuperare un’istanza dell’Ordine e quindi di effettuare Order.Customer.FirstName senza dover fare esplicitamente un join, il che è estremamente conveniente.

Quindi, per riassumere, le mie domande sono:

  1. Ci sono degli svantaggi significativi nell’uso di associazioni indipendenti? e…
  2. Se non ce ne sono, quale sarebbe la ragione di utilizzare le associazioni di chiavi estere?

Se vuoi sfruttare appieno l’ORM, utilizzerai sicuramente il riferimento Entity:

 public class Order { public int ID { get; set; } public Customer Customer { get; set; } // <-- Customer object ... } 

Una volta generato un modello di quadro da un database con FK, genererà sempre riferimenti di quadro. Se non si desidera utilizzarli, è necessario modificare manualmente il file EDMX e aggiungere proprietà che rappresentano FK. Almeno questo era il caso in Entity Framework v1 in cui erano consentite solo le associazioni indipendenti.

Entity Framework v4 offre un nuovo tipo di associazione chiamata Foreign key association. La differenza più evidente tra l'associazione di chiave indipendente e quella straniera è nella class Ordine:

 public class Order { public int ID { get; set; } public int CustomerId { get; set; } // <-- Customer ID public Customer Customer { get; set; } // <-- Customer object ... } 

Come puoi vedere, hai sia la proprietà FK che il riferimento all' quadro. Ci sono più differenze tra due tipi di associazioni:

Associazione indipendente

  • È rappresentato come object separato in ObjectStateManager . Ha il proprio EntityState !
  • Quando costruisci un'associazione hai sempre bisogno di entitites da entrambe le parti dell'associazione
  • Questa associazione è mappata allo stesso modo dell'entity framework.

Associazione chiave esterna

  • Non è rappresentato come object separato in ObjectStateManager . A causa di ciò è necessario seguire alcune regole speciali.
  • Quando costruisci un'associazione non hai bisogno di entrambi i fini dell'associazione. È sufficiente avere un'entity framework figlio e un PK dell' quadro padre, ma il valore PK deve essere univoco. Pertanto, quando si utilizza l'associazione di chiavi esterne, è necessario assegnare anche ID univoci temporanei alle entity framework di nuova generazione utilizzate nelle relazioni.
  • Questa associazione non è mappata ma definisce invece i vincoli referenziali.

Se si desidera utilizzare l'associazione di chiavi esterne, è necessario selezionare Includi colonne chiave esterna nel modello in Creazione guidata modello dati quadro.

Modificare:

Ho scoperto che la differenza tra questi due tipi di associazioni non è molto nota, quindi ho scritto un breve articolo che copre questo con maggiori dettagli e la mia opinione su questo.

Usali entrambi. E rendere i riferimenti di entity framework virtuali per consentire il caricamento lazy. Come questo:

 public class Order { public int ID { get; set; } public int CustomerID { get; set; } public virtual Customer Customer { get; set; } // <-- Customer object ... } 

Ciò consente di risparmiare su ricerche DB non necessarie, consente il caricamento lento e consente di vedere / impostare facilmente l'ID se si sa cosa si vuole che sia. Si noti che avere entrambi non modifica la struttura della tabella in alcun modo.

L’associazione indipendente non funziona bene con AddOrUpdate che viene solitamente utilizzato nel metodo Seed . Quando il riferimento è un elemento esistente, verrà reinserito.

 // Existing customer. var customer = new Customer { Id = 1, Name = "edit name" }; db.Set().AddOrUpdate(customer); // New order. var order = new Order { Id = 1, Customer = customer }; db.Set().AddOrUpdate(order); 

Il risultato è che il cliente esistente verrà reinserito e il nuovo cliente (reinserito) sarà associato al nuovo ordine.


A meno che non usiamo l’associazione di chiave esterna e assegniamo l’id.

  // Existing customer. var customer = new Customer { Id = 1, Name = "edit name" }; db.Set().AddOrUpdate(customer); // New order. var order = new Order { Id = 1, CustomerId = customer.Id }; db.Set().AddOrUpdate(order); 

Abbiamo il comportamento previsto, il cliente esistente sarà associato al nuovo ordine.

Sono favorevole all’approccio a oggetti per evitare ricerche non necessarie. Gli oggetti delle proprietà possono essere compilati con la stessa facilità quando si chiama il metodo factory per creare l’intera quadro (utilizzando un semplice codice di callback per le quadro nidificate). Non ci sono svantaggi che posso vedere tranne che per l’utilizzo della memoria (ma dovresti mettere in cache i tuoi oggetti giusto?). Quindi, tutto ciò che si sta facendo è sostituire lo stack per l’heap e ottenere un guadagno in termini di prestazioni dall’assenza di ricerche. Spero che abbia senso.