Question Code d'abord: associations indépendantes et associations clés étrangères?


J'ai un débat mental avec moi chaque fois que je commence à travailler sur un nouveau projet et que je conçois mes POCO. J'ai vu de nombreux tutoriels / exemples de code qui semblent favoriser associations de clés étrangères:

Association de clés étrangères

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

Par opposition à associations indépendantes:

Association indépendante

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

J'ai travaillé avec NHibernate dans le passé et j'ai utilisé des associations indépendantes, qui non seulement ressentent plus d'OO, mais (avec un chargement différé) ont l'avantage de me donner accès à tout l'objet du client, et pas seulement à son identifiant. Cela me permet, par exemple, de récupérer une instance Order puis de faire Order.Customer.FirstName sans avoir à faire de jointure explicitement, ce qui est extrêmement pratique.

Donc, pour résumer, mes questions sont les suivantes:

  1. Y at-il des inconvénients importants dans en utilisant des associations indépendantes? et...
  2. S'il n'y en a pas, quoi serait la raison d'utiliser des associations de clés étrangères du tout?

98
2018-03-12 10:35


origine


Réponses:


Si vous souhaitez tirer pleinement parti d'ORM, vous utiliserez certainement la référence d'entité:

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

Une fois que vous générez un modèle d'entité à partir d'une base de données avec des FK, il générera toujours des références d'entité. Si vous ne souhaitez pas les utiliser, vous devez modifier manuellement le fichier EDMX et ajouter des propriétés représentant les FK. C'était du moins le cas dans Entity Framework v1 où seules les associations indépendantes étaient autorisées.

Framework d'entité v4 propose un nouveau type d'association appelé association de clés étrangères. La différence la plus évidente entre l'association de clés indépendante et étrangère est dans la classe d'ordre:

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

Comme vous pouvez le voir, vous avez à la fois la propriété FK et la référence d'entité. Il y a plus de différences entre deux types d'associations:

Association indépendante

  • Il est représenté comme objet séparé dans ObjectStateManager. Il a le sien EntityState!
  • Lors de la création d'une association, vous avez toujours besoin d'autorités des deux extrémités de l'association
  • Cette association est mappée de la même manière que l'entité.

Association de clés étrangères

  • Il n'est pas représenté comme objet séparé dans ObjectStateManager. Pour cette raison, vous devez suivre certaines règles spéciales.
  • Lorsque vous créez une association, vous n'avez pas besoin des deux fins de l'association. Il suffit d'avoir une entité enfant et une PK d'entité parente, mais la valeur PK doit être unique. Ainsi, lors de l'utilisation d'une association de clés étrangères, vous devez également affecter des identifiants uniques temporaires aux entités nouvellement générées utilisées dans les relations.
  • Cette association n'est pas mappée mais définit des contraintes référentielles.

Si vous souhaitez utiliser une association de clés étrangères, vous devez cocher Inclure des colonnes de clé étrangère dans le modèle dans l'Assistant Modèle de données d'entité.

Modifier:

J'ai trouvé que la différence entre ces deux types d'associations n'est pas très connue, donc J'ai écrit un court article couvrant cela avec plus de détails et ma propre opinion à ce sujet.


104
2018-03-12 11:43



Utilise les deux. Et faites de votre entité des références virtuelles pour permettre un chargement différé. Comme ça:

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

Cela économise des recherches inutiles sur la base de données, permet un chargement paresseux et vous permet de voir / définir facilement l'ID si vous savez ce que vous voulez qu'il soit. Notez que le fait d'avoir les deux ne change en rien votre structure de table.


33
2018-05-13 15:59



L'association indépendante ne fonctionne pas bien avec AddOrUpdate qui est généralement utilisé dans Seed méthode. Lorsque la référence est un élément existant, il sera réinséré.

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

// New order.
var order = new Order { Id = 1, Customer = customer };
db.Set<Order>().AddOrUpdate(order);

Le résultat est que le client existant sera réinséré et que le nouveau client (réinséré) sera associé à la nouvelle commande.


A moins d'utiliser l'association de clé étrangère et d'affecter l'identifiant.

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

// New order.
var order = new Order { Id = 1, CustomerId = customer.Id };
db.Set<Order>().AddOrUpdate(order);

Nous avons le comportement attendu, le client existant sera associé à la nouvelle commande.


8
2017-08-18 06:19



Je privilégie l'approche objet pour éviter les recherches inutiles. Les objets de propriété peuvent être remplis aussi facilement lorsque vous appelez votre méthode d'usine pour créer l'entité entière (en utilisant un code de rappel simple pour les entités imbriquées). Il n'y a aucun inconvénient que je peux voir, sauf pour l'utilisation de la mémoire (mais vous cachez vos objets correctement?). Ainsi, tout ce que vous faites est de remplacer la pile par le tas et de gagner en performance en ne réalisant pas de recherche. J'espère que cela a du sens.


4
2018-03-12 10:43