web-dev-qa-db-fra.com

Conventions de dénomination, modélisation et héritage DTO

Nous construisons une application Web utilisant AngularJS, C #, l'API Web ASP.Net et Fluent NHibernate .. Nous avons décidé d'utiliser des DTO pour transférer des données vers la couche de présentation (vues angulaires) .. J'ai quelques doutes quant à la structuration générale et la dénomination des DTO . Voici un exemple pour illustrer mon scénario . Disons que j'ai une entité de domaine appelée Client qui ressemble à:

public class Customer
    {
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
        public virtual Address Address { get; set; }
        public virtual ICollection<Account> Accounts { get; set; }
    }

Maintenant, dans ma couche de vues/présentation, je dois récupérer différentes versions du client, telles que:

1) Identifiant et nom 2) Identifiant, nom et adresse 3) Identifiant, nom, adresse et comptes

J'ai créé un ensemble de DTO pour accomplir ceci:

public class CustomerEntry
{
    public  int Id { get; set; }
    public  string Name { get; set; }
}

public class CustomerWithAddress : CustomerEntry
{
    public AddressDetails Address { get; set; }
}

public class CustomerWithAddressAndAccounts : CustomerWithAddress
{
    public ICollection<AccountDetails> Accounts { get; set; }
}

AddressDetails et AccountDetails sont des DTO qui possèdent toutes les propriétés de leurs entités de domaine correspondantes.

Cela fonctionne très bien pour les requêtes et les extractions de données; la question est qu'est-ce que j'utilise pour les insertions et les mises à jour. Lors de la création d'un nouvel enregistrement client, le nom et l'adresse sont obligatoires et les comptes sont facultatifs. En d'autres termes, j'ai besoin d'un objet avec toutes les propriétés du client. D'où la confusion:

1) Que dois-je utiliser pour les insertions et les mises à jour? Le DTO CustomerWithAddressAndAccounts contient tout, mais son nom semble un peu gênant pour être utilisé pour des insertions/mises à jour. 

2) Est-ce que je crée un autre DTO? Si tel est le cas, ne s'agit-il pas d'une duplication, le nouveau DTO ressemblant exactement à CustomerWithAddressAndAccounts?

3) Dernier point, mais non le moindre, la structure de succession DTO décrite ci-dessus semble-t-elle être un bon choix pour l'exigence? Existe-t-il d'autres moyens de modéliser cela?

J'ai lu d'autres articles sur ce sujet mais je ne pouvais pas avancer beaucoup. Une des choses que j'ai choisies de faire était d'éviter d'utiliser le suffixe "DTO" dans les noms de classe ... Je pense que c'est un peu superflu .

Aimerais entendre vos pensées

Merci 

29
Sennin

La recommandation est que vous ne devriez avoir qu’une classe DTO pour chaque entité suffixé de DTO par exemple. CustomerEntryDTO pour la Customerentity (mais vous pouvez certainement utiliser des hiérarchies d'héritage selon le choix et les exigences).

De plus, ajoutez un type abstrait DTOBase de classe de base ou une interface; et n'utilisez pas de telles hiérarchies d'héritage profond pour chaque adresse, compte et autres propriétés à inclure dans des objets DTO enfants. Incluez plutôt ces propriétés dans la même classe CustomerEntryDTO (si possible) ci-dessous:

[Serializable]
public class CustomerEntryDTO : DTOBase, IAddressDetails, IAccountDetails
{
    public  int Id { get; set; }
    public  string Name { get; set; }
    public AddressDetails Address { get; set; } //Can remain null for some Customers
    public ICollection<AccountDetails> Accounts { get; set; } //Can remain null for some Customemer
}

De plus, votre DTO devrait être sérialisable pour pouvoir être passé à travers les limites du processus.

Pour plus sur le modèle DTO, reportez-vous aux articles ci-dessous:

Objet de transfert de données

MSDN

Edit: Au cas où vous ne voudriez pas envoyer certaines propriétés par fil (je sais que vous en auriez besoin de manière conditionnelle, vous auriez besoin d'en explorer davantage), vous pouvez les exclure du Mécanisme de sérialisation utilisant des attributs tels que NonSerialized (mais cela ne fonctionne que sur les champs et non sur les propriétés, voir l'article de la solution de contournement à utiliser avec les propriétés: Non sérialisé sur la propriété ). Vous pouvez également créer votre propre attribut personnalisé, tel que ExcludeFromSerializationAttribute, et l'appliquer à des propriétés que vous ne souhaitez pas envoyer chaque fois par fil, en fonction de certaines règles/conditions. Voir aussi:Sérialisation xml conditionnelle

Edit 2: Utilisez des interfaces pour séparer les différentes propriétés de la classe CustomerEntryDTO. Voir le principe de séparation des interfaces sur Google ou MSDN. Je vais essayer de mettre un exemple d'explication plus tard.

11
VS1

Que dois-je utiliser pour les insertions et les mises à jour?

  1. Les opérations de service sont généralement définies en relation très étroite avec les opérations commerciales. La langue des affaires ne parle pas d’insert et de mise à jour, pas plus que les services.

  2. Le service de gestion client aura probablement une opération Register qui prend le nom du client et peut-être d'autres paramètres facultatifs.

Est-ce que je crée un autre DTO?

Oui, vous devriez créer un autre DTO.

Parfois, le contrat d’exploitation du service peut être suffisant et il n’est pas nécessaire de définir un DTO distinct pour une opération particulière:

function Register(UserName as String, Address as Maybe(of String)) as Response

Mais la plupart du temps, il est préférable de définir une classe DTO séparée même pour une seule opération de service:

class RegisterCommand
    public UserName as String
    public Address as Maybe(of String)
end class

function Register(Command as RegisterCommand) as Response

RegisterCommand DTO peut ressembler beaucoup à CustomerWithAddress DTO car il a les mêmes champs, mais en réalité, ces 2 DTO ont des significations très différentes et ne se substituent pas. 

Par exemple, CustomerWithAddress contient AddressDetails, alors qu'une simple représentation d'adresse String peut suffire à inscrire un client.

L'utilisation d'un DTO distinct pour chaque opération de service prend plus de temps à écrire mais est plus facile à gérer.

0
Lightman