Как спроектировать объекты передачи данных на уровне бизнес-логики - PullRequest
10 голосов
/ 22 февраля 2009

DTO

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

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

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

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

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

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

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

Вставить DTO, Обновить DTO, Удалить DTO, 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.ActedObject.

Это хороший подход? Одна проблема состоит в том, что кажется, что он передает много данных назад и вперед, что является избыточным (когда это просто идентификатор). Я не думаю, что добавление свойства "int NewID" было бы чистым, потому что некоторые вставки не будут иметь такой автоинкрементный ключ. Другая проблема в том, что я не думаю, что веб-сервисы справятся с этим хорошо? Я полагаю, что они просто вернут базовый DTO для ActedObject в классе Result, а не производный DTO. Я полагаю, что я мог бы решить эту проблему, имея МНОЖЕСТВО различных типов объектов Result (возможно, полученных из базового Result и унаследовавших свойство Error), но это не кажется очень чистым.

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

Ответы [ 2 ]

3 голосов
/ 22 февраля 2009

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

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

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

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

1 голос
/ 22 февраля 2009

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

Q2: Сконфигурируйте ваши контракты с данными Response для возврата нового пользовательского типа с вашими первичными ключами и т. Д. ... WCF также можно настроить для выдачи исключений обратно в интерфейс.

...