Подтвердить что ты не робот

Соглашения об именах DTO, моделирование и наследование

Мы создаем веб-приложение, используя AngularJS, С#, ASP.Net Web API и Fluent NHibernate. Мы решили использовать DTO для передачи данных на уровень представления (angular views). У меня было несколько сомнений относительно общего структурирования и обозначения DTO. Вот пример, иллюстрирующий мой сценарий. Допустим, у меня есть объект домена Customer, который выглядит следующим образом:

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; }
    }

Теперь, в моем представлении/слое представления, мне нужно получить различные вкусы клиента, например:

1) Идентификатор и имя  2) Идентификатор, имя и адрес  3) Идентификатор, имя, адрес и учетные записи

Я создал набор DTO для выполнения этого:

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 и AccountDetails являются DTO, которые имеют все свойства своих соответствующих объектов домена.

Это отлично подходит для запросов и извлечения данных; вопрос в том, что я использую для вставок и обновлений. Во время создания новой записи клиента имя и адрес являются обязательными, а учетные записи являются необязательными. Иными словами, мне нужен объект со всеми свойствами клиента. Отсюда путаница:

1) Что я могу использовать для вставки и обновления? В CustomerWithAddressAndAccounts DTO есть все, но его имя кажется немного неудобным для вставки/обновления.

2) Я создаю еще один DTO.. ​​если я это сделаю, не будет ли это дублирование, поскольку новый DTO будет точно таким же, как CustomerWithAddressAndAccounts?

3) И последнее, но не менее важное: описывает ли описанное выше наследование наследования DTO как подходящее для этого требование? Есть ли другие способы моделирования этого?

Я прочитал другие сообщения по этой теме, но не смог добиться больших успехов. Одна вещь, которую я делал, заключалась в том, чтобы избежать использования суффикса "DTO" в именах классов. Я думаю, что это немного лишнее.

Хотелось бы услышать ваши мысли

Спасибо

4b9b3361

Ответ 1

Рекомендация состоит в том, что вам должен быть только один класс DTO для каждого объекта , суффиксного с DTO, например. CustomerEntryDTO для Customer entity (но вы, безусловно, можете использовать иерархии наследования в соответствии с выбором и требованиями).

Кроме того, добавьте абстрактный DTOBase вид базового класса или интерфейса; и не используйте такие глубокие иерархии наследования для каждого Адреса, Счета и других свойств, которые должны быть включены в дочерние DTO. Скорее, включите эти свойства в тот же класс CustomerEntryDTO (если возможно), как показано ниже:

[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
}

Кроме того, ваши DTO должны быть сериализуемыми для передачи через границы процесса.

Подробнее о шаблоне DTO см. ниже в статьях:

Объект передачи данных

MSDN

Edit: Если вы не хотите отправлять определенные свойства по проводу (я знаю, что вам нужно это условно, поэтому вам нужно будет изучить больше об этом), вы можете исключить их из механизма Serialization, используя такие атрибуты, как NonSerialized (но он работает только по полям, а не по свойствам, см. статью об использовании для использования со свойствами: NonSerialized on свойство). Вы также можете создать свой собственный настраиваемый атрибут, например ExcludeFromSerializationAttribute, и применить его к свойствам, которые вы не хотите отправлять каждый раз по проводке на основе определенных правил/условий. Также см.: Условная сериализация XML

Изменить 2: Используйте интерфейсы для разделения различных свойств в одном классе CustomerEntryDTO. См. Принцип разделения интерфейса в Google или MSDN. Я попытаюсь позже поместить образец объяснения.

Ответ 2

Что касается вашего элемента 1, для вставок и обновлений лучше использовать шаблон команды. Согласно CQRS, вам не нужны DTO. Рассмотрим эту схему: CQRS — basic patterns через blogs.msdn.com

Ответ 3

Что я могу использовать для вставки и обновления?

  • Операции обслуживания обычно определяются в очень тесном отношении к бизнес-операциям. Деловой язык не говорит в терминах "вставок" и "обновлений", а также служб.

  • Служба управления клиентами, вероятно, будет иметь некоторую операцию Register, которая принимает имя клиента и, возможно, некоторые другие необязательные параметры.

Создать другой DTO?

Да, вы должны создать еще один DTO.

Иногда может быть достаточно контракта на обслуживание, и нет необходимости определять отдельный DTO для конкретной операции:

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

Но в большинстве случаев лучше определить отдельный класс DTO даже для одной операции:

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

function Register(Command as RegisterCommand) as Response

RegisterCommand DTO может выглядеть очень похоже на CustomerWithAddress DTO, потому что он имеет те же поля, но на самом деле эти 2 DTO имеют очень разные значения и не заменяют друг друга.

Например, CustomerWithAddress содержит AddressDetails, в то время как простого представления адреса String может быть достаточно для регистрации клиента.

Использование отдельного DTO для каждой операции обслуживания занимает больше времени для записи, но проще в обслуживании.