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 les 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 ... } 

Contrairement aux 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 access à tout l’object du client, et pas seulement à son identifiant. Cela me permet, par exemple, d’extraire une instance Order, puis de faire Order.Customer.FirstName sans avoir à faire explicitement une jointure, ce qui est extrêmement pratique.

Donc, pour résumer, 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?

    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 firebase database 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 append 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 object séparé dans ObjectStateManager . Il a son propre 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é en tant qu'object distinct 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é étrangère, vous devez cocher la case Inclure les 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, j'ai donc écrit un court article à ce sujet avec plus de détails et ma propre opinion à ce sujet.

    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 firebase database, 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.

    L’association indépendante ne fonctionne pas bien avec AddOrUpdate qui est généralement utilisé dans la méthode Seed . 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().AddOrUpdate(customer); // New order. var order = new Order { Id = 1, Customer = customer }; db.Set().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.


    À moins d’utiliser l’association de clé étrangère et d’atsortingbuer l’identifiant.

      // 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); 

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

    Je privilégie l’approche object pour éviter les recherches inutiles. Les objects 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 nestedes). Il n’y a aucun inconvénient que je peux voir, sauf pour l’utilisation de la mémoire (mais vous cachez vos objects correctement?). Ainsi, tout ce que vous faites est de remplacer la stack par le tas et de gagner en performance en ne réalisant pas de recherche. J’espère que cela a du sens.