Как спроектировать объекты передачи данных на уровне бизнес-логики

StackOverflow https://stackoverflow.com/questions/574520

Вопрос

DTO

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

Я использую LLBLGen для создания уровня доступа к данным (с использованием SQL Server 2008).Цель состоит в том, чтобы создать уровень бизнес-логики, который защищает веб-приложение от деталей DAL и, конечно же, обеспечивает дополнительный уровень проверки за пределами DAL.Кроме того, насколько я могу судить прямо сейчас, веб-служба по сути будет тонкой оболочкой над BLL.

Разумеется, DAL имеет собственный набор объектов сущностей, например CustomerEntity, ProductEntity и т. д.Однако я не хочу, чтобы уровень представления имел прямой доступ к этим объектам, поскольку они содержат методы, специфичные для DAL, а сборка специфична для DAL и так далее.Итак, идея состоит в том, чтобы создать объекты передачи данных (DTO).Идея состоит в том, что это будут, по сути, простые старые объекты C#/.NET, которые имеют все поля, скажем, CustomerEntity, которые на самом деле являются таблицей базы данных Customer, но ничего другого, за исключением, возможно, некоторых свойств IsChanged/IsDirty.Итак, будут CustomerDTO, ProductDTO и т. д.Я предполагаю, что они будут наследоваться от базового класса DTO.Я думаю, что смогу сгенерировать их с помощью какого-нибудь шаблона для LLBLGen, но пока не уверен в этом.

Итак, идея состоит в том, что BLL раскроет свою функциональность, принимая и возвращая эти объекты DTO.Я думаю, что веб-служба будет обрабатывать преобразование этих объектов в XML для третьих сторон, использующих ее, многие из них могут не использовать .NET (кроме того, некоторые вещи будут вызываться скриптами из вызовов AJAX в веб-приложении с использованием JSON).

Я не уверен, как лучше всего это спроектировать и как именно двигаться дальше.Вот некоторые проблемы:

1) Как это должно быть представлено клиентам (уровень представления и код веб-службы)

Я думал, что будет один публичный класс, который будет иметь эти методы, и каждый вызов будет атомарной операцией:

InsertDTO, UpdateDTO, DeleteDTO, GetProducts, GetProductByCustomer и т. д.

Затем клиенты просто вызывали эти методы и передавали соответствующие аргументы, обычно DTO.

Это хороший и работоспособный подход?

2) Что вернуть из этих методов?Очевидно, что методы типа Get/Fetch вернут DTO.А как насчет вставок?Частью подписи может быть:

InsertDTO(DTO dto)

Однако при вставке что должно быть возвращено?Я хочу получать уведомления об ошибках.Однако для некоторых таблиц я использую автоинкрементные первичные ключи (однако некоторые таблицы имеют естественные ключи, особенно «многие ко многим»).

Одним из вариантов, о котором я думал, был класс Result:

class Result
{
    public Exception Error {get; set;}
    public DTO AffectedObject {get; set;}
}

Таким образом, при вставке DTO получит набор свойств get ID (например, CustomerDTO.CustomerID), а затем вставит этот объект результата.Клиент узнает, произошла ли ошибка, если Result.Error != null, а затем узнает идентификатор из свойства Result.AffectedObject.

Это хороший подход?Одна из проблем заключается в том, что создается впечатление, что он передает туда и обратно много избыточных данных (когда это просто идентификатор).Я не думаю, что добавление свойства «int NewID» будет чистым, потому что некоторые вставки не будут иметь такого автоинкрементного ключа.Другая проблема заключается в том, что я не думаю, что веб-службы справятся с этим хорошо?Я считаю, что они просто вернут базовый DTO для AffectedObject в классе Result, а не производный DTO.Полагаю, я мог бы решить эту проблему, имея МНОГО различных типов объектов Result (возможно, полученных из базового Result и наследующих свойство Error), но это не кажется очень чистым.

Хорошо, я надеюсь, что это не слишком многословно, но я хочу внести ясность.

Это было полезно?

Решение

1:Это довольно стандартный подход, который хорошо подходит для реализации «репозитория» для лучшего подхода к модульному тестированию.

2:Исключения (которые, кстати, должны быть объявлены как «ошибки» на границе WCF) будут возникать автоматически.Вам не нужно решать это напрямую.Для данных существует три распространенных подхода:

  • использовать ref по контракту (не очень красиво)
  • вернуть (обновленный) объект, т.е. public DTO SomeOperation(DTO item);
  • возвращать только обновленную идентификационную информацию (первичный ключ/метку времени/и т. д.)

Во всем этом есть одна особенность: для каждой операции не требуется использовать другой тип (сравните с вашим Result class, который необходимо будет дублировать для каждого DTO).

Другие советы

Вопрос 1:Чтобы решить эту проблему, вы можете думать о своих составных типах контракта данных WCF как об DTO.Таким образом, ваш уровень пользовательского интерфейса имеет доступ только к свойствам DataMember DataContract.Ваши атомарные операции будут методами, предоставляемыми вашим интерфейсом WCF.

Вопрос 2:Настройте свои контракты данных ответа так, чтобы они возвращали новый пользовательский тип с вашими первичными ключами и т. д.WCF также можно настроить для возврата исключений в пользовательский интерфейс.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top