web-dev-qa-db-fra.com

Code First: Associations indépendantes vs associations clés étrangères?

J'ai un débat mental avec moi-même 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é étrangère

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 utilisé des associations indépendantes, qui non seulement se sentent plus OO, mais ont également (avec un chargement paresseux) l'avantage de me donner accès à l'ensemble de l'objet Client, au lieu de simplement son ID. Cela me permet, par exemple, de récupérer une instance de commande, puis de faire Order.Customer.FirstName sans avoir à faire explicitement une jointure, ce qui est extrêmement pratique.

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

  1. Y a-t-il des inconvénients importants à utiliser des associations indépendantes? et...
  2. S'il n'y en a pas, quelle serait la raison d'utiliser des associations de clés étrangères?
100
Daniel Liuzzi

Si vous souhaitez profiter pleinement de l'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ère 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.

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

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 disposez à la fois d'une propriété FK et d'une référence d'entité. Il existe plus de différences entre deux types d'associations:

Association indépendante

  • Il est représenté comme un objet séparé dans ObjectStateManager. Il a son propre EntityState!
  • Lorsque vous créez une association, vous avez toujours besoin de droits 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é étrangère

  • Il n'est pas représenté comme un objet séparé dans ObjectStateManager. Pour cette raison, vous devez suivre certaines règles spéciales.
  • Lors de la création d'une association, vous n'avez pas besoin des deux extrémités de l'association. Il suffit d'avoir l'entité enfant et le PK de l'entité parent mais la valeur PK doit être unique. Ainsi, lorsque vous utilisez l'association de clés étrangères, vous devez également attribuer des ID 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 plutôt des contraintes référentielles.

Si vous souhaitez utiliser l'association de clé étrangère, vous devez cocher Inclure les colonnes de clé étrangère dans le modèle dans l'assistant de 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 bien connue alors j'ai écrit un court article couvrant cela avec plus de détails et ma propre opinion à ce sujet.

106
Ladislav Mrnka

Utilise les deux. Et rendez vos références d'entité virtuelles pour permettre un chargement paresseux. Comme ça:

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

Cela permet d'économiser sur les recherches de base de données inutiles, 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 les deux ne modifient en rien la structure de votre table.

33
Seth Paulson

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, elle sera réinsérée.

// 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 qu'un nouveau client (réinséré) sera associé à une nouvelle commande.


Sauf si nous utilisons l'association de clé étrangère et assignons l'ID.

 // 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é à une nouvelle commande.

8
Yuliam Chandra

Je privilégie l'approche objet pour éviter les recherches inutiles. Les objets de propriété peuvent être tout aussi facilement remplis lorsque vous appelez votre méthode d'usine pour construire 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 mettriez en cache vos objets non?). Donc, tout ce que vous faites est de remplacer la pile par le tas et de gagner en performances en n'effectuant pas de recherches. J'espère que cela a du sens.

4
CarneyCode