web-dev-qa-db-fra.com

Est-ce une bonne pratique d'utiliser des objets d'entité comme objets de transfert de données?

Je me demande parce que si c'est le cas, pourquoi Entity Framework n'offre pas de logique pour créer un nouvel objet avec les mêmes propriétés pour transférer des données entre les couches?

J'utilise les objets d'entité que je génère avec le framework d'entité.

30
user2484998

C'est à vous de décider.

La plupart des gens vous diront que ce n'est pas une bonne pratique mais vous pouvez vous en tirer dans certains cas.

EF n'a jamais bien joué avec DDD pour plusieurs raisons, mais deux se distinguent: vous ne pouvez pas avoir de constructeurs paramétrés sur vos entités et vous ne pouvez pas encapsuler des collections. DDD s'appuie sur cela, car le modèle de domaine doit inclure à la fois les données et le comportement.

D'une certaine manière, EF vous oblige à avoir un modèle de domaine anémique et dans ce cas, vous pouvez utiliser les entités en tant que DTO. Vous pouvez rencontrer certains problèmes si vous utilisez les propriétés de navigation, mais vous pouvez sérialiser ces entités et les envoyer par câble. Ce n'est peut-être pas pratique cependant. Vous devrez contrôler la sérialisation de chaque entité qui possède des propriétés que vous n'avez pas besoin d'envoyer. Le moyen le plus simple consiste à concevoir simplement des classes distinctes adaptées au transfert de données. Des bibliothèques comme AutoMapper sont créées à cet effet.

Par exemple: supposons que vous ayez une classe appelée Person avec la définition suivante:

public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public DateTime DateOfBirth { get; get; }

    // plus a bunch of other properties relevant about a person
}

En supposant que vous souhaitiez afficher une liste d'employés quelque part, il peut être pratique d'envoyer uniquement les Id, FirstName et LastName. Mais vous devrez envoyer toutes les autres propriétés non pertinentes. Ce n'est pas un gros problème si vous ne vous souciez pas de la taille de la réponse, mais l'idée générale est d'envoyer uniquement les données pertinentes. D'un autre côté, vous pouvez concevoir une API qui renvoie une liste de personnes et, dans ce cas, l'envoi de toutes les propriétés peut être nécessaire, il est donc judicieux de sérialiser et d'envoyer les entités. Dans ce cas, la création d'une classe DTO est discutable. Certaines personnes aiment mélanger les entités et les DTO, d'autres non.

Pour répondre à votre question mise à jour, EF est un ORM. Son travail consiste à mapper des enregistrements de base de données à des objets et vice versa. Ce que vous faites avec ces objets avant et après avoir traversé EF ne fait pas partie de ses préoccupations. Cela ne devrait pas non plus.

24
devnull

Non, ça ne l'est pas.

Idéalement, les DTO correspondront à vos référentiels de persistance (aka, vos tables de base de données).

Mais vos cours d'affaires ne sont pas nécessairement un match. Vous pourriez avoir besoin de classes supplémentaires, ou de classes séparées ou jointes à ce que vous avez dans la base de données. Si votre application est petite, vous ne verrez peut-être pas vraiment ce genre de problèmes, mais dans les applications moyennes à grandes, cela se produira souvent.

Une autre chose est que les DTO font partie du domaine de tout ce qui traite de la persistance, tandis que votre couche métier ne devrait rien savoir à leur sujet.

Non, c'est une mauvaise pratique.

Certaines raisons:

  1. Les nouveaux champs d'entité seront dans le Dto, par défaut. Utiliser l'entité signifie que toutes les informations seront disponibles pour être consommées par défaut. Cela peut vous conduire à exposer des informations sensibles ou, au moins, à gonfler votre contrat d'API, avec beaucoup d'informations qui ne sont pas utilisées pour qui consomme l'API. Bien sûr, vous pouvez ignorer les champs à l'aide d'annotations (comme @JsonIgnore du monde Java), mais cela mène au problème suivant ...
  2. Beaucoup d'annotations/conditions/contrôles sur l'entité. Vous devez contrôler ce que vous souhaitez envoyer sur Dto, lorsqu'un nom d'attribut a changé (cela rompra le contrat), ajouter un attribut qui ne provient pas de l'entité, l'ordre des attributs, etc. Bientôt, vous verrez votre simple entité avec beaucoup d'annotations, de champs supplémentaires et à chaque fois sera plus difficile de comprendre ce qui se passe.
  3. Moins de flexibilité. Avec un Dto, vous êtes libre de diviser les informations en plusieurs classes, de changer les noms d'attributs, d'ajouter de nouveaux attributs, etc. Vous ne pouvez pas faire cela si facilement avec une entité comme Dto.
  4. Non optimisé. Votre entité sera toujours plus grande qu'un simple Dto. Ainsi, vous aurez toujours plus d'informations à ignorer/sérialiser et probablement plus d'informations à transmettre.
  5. Problèmes paresseux. En utilisant l'entité de certains frameworks (comme Hibernate), si vous essayez de récupérer des informations qui n'étaient pas chargées paresseusement dans une transaction de base de données auparavant, le proxy ORM ne sera pas attaché à la transaction et vous recevrez une sorte d '"exception paresseuse" juste pour appeler une méthode get de l'entité.

Il est donc plus facile et sûr d'utiliser une sorte d'outil de mappage pour vous aider dans ce travail, en mappant les champs d'entité à un Dto.

6
Dherik

C'est en fait une très mauvaise idée. Martin Fowler a un article sur les DTO locaux .

Pour faire court, DTO Pattern a été utilisé pour transférer des données en dehors du processus, par exemple sur le fil et non entre des couches à l'intérieur du même processus.

5

Pour compléter ce qu'a dit @Dherik, les principaux problèmes liés à l'utilisation d'objets d'entité comme objets de transfert de données sont les suivants:

  1. Dans une transaction, vous prenez le risque de valider les modifications apportées à votre entité car vous l'utilisez en tant que DTO (même si vous pouvez détacher l'entité de la session dans une transaction, la plupart du temps vous devrez vérifier cet état avant toute modification sur votre entité-DTO et assurez-vous que vous n'êtes pas dans une transaction ou que la session a été fermée si vous ne voulez pas que les modifications soient persistées).

  2. La taille des données que vous partagez entre le client et le serveur: parfois, vous ne voulez pas envoyer tout le contenu d'une entité au client pour minimiser la taille de la réponse de la demande. La séparation du DTO de l'entité est plus flexible, afin de spécialiser les données que vous souhaitez envoyer dans certains cas d'utilisation.

  3. Visibilité et maintenance: vous devez gérer vos annotations jpa/hibernate sur les champs de votre entité et maintenir les annotations jackson à sérialiser dans json au même endroit (même si vous pouvez les séparer de l'implémentation d'entité en les plaçant dans l'interface héritée par le entité). Ensuite, si vous modifiez votre contenu DTO en ajoutant un nouveau champ, une autre personne peut probablement penser que c'est un champ de l'entité, donc un champ de la table concernée dans votre base de données (même si vous pouvez utiliser le @Transient annotation sur tous vos champs DTO pour le cas ..!).

À mon avis, cela crée du bruit lorsque vous lisez l'entité, mais mon avis est sûrement subjectif.

1
Charles Vuillecard