Данные WCF Контракт и Справочные данные? - PullRequest
12 голосов
/ 17 июня 2009

Запрос отзывов / опций / комментариев относительно «лучшего» шаблона для использования в качестве справочных данных в моих службах.

Что я подразумеваю под справочными данными?

Давайте используем Northwind в качестве примера. Заказ связан с Клиентом в базе данных. Когда я внедряю свою Службу заказов, в некоторых случаях мне понадобится ссылка «полный» Клиент из Заказа, а в других случаях мне просто нужна ссылка на Клиента (например, пара ключ / значение).

Например, если бы я выполнял GetAllOrders (), я бы не хотел возвращать полностью заполненный Заказ, я хотел бы вернуть облегченную версию Заказа, содержащую только справочные данные для Клиента каждого заказа. Если бы я использовал метод GetOrder (), я бы, вероятно, хотел бы заполнить данные о клиентах, потому что, скорее всего, потребителю этого метода он может понадобиться. Могут быть и другие ситуации, когда я могу попросить, чтобы данные о клиенте заполнялись во время определенных вызовов методов, но оставлялись для других.

Вот что я придумал:

[DataContract]
public OrderDTO
{
    [DataMember(Required)]
    public CustomerDTO;

    //etc..
}

[DataContract]
public CustomerDTO
{
    [DataMember(Required)]
    public ReferenceInfo ReferenceInfo;

    [DataMember(Optional)]
    public CustomerInfo CustomerInfo;
}

[DataContract]
public ReferenceInfo
{
    [DataMember(Required)]
    public string Key;

    [DataMember(Required)]
    public string Value;
}

[DataContract]
public CustomerInfo 
{
    [DataMember(Required)]
    public string CustomerID;

    [DataMember(Required)]
    public string Name;

    //etc....
}

Мысль здесь заключается в том, что, поскольку ReferenceInfo (который является общей парой ключ / значение) всегда требуется в CustomerDTO, у меня всегда будет ReferenceInfo. Это дает мне достаточно информации, чтобы получить детали клиента позже, если это необходимо. Недостатком того, что CustomerDTO требует ReferenceInfo, является то, что это может быть излишним, когда я получаю полный CustomerDTO (т.е. с заполненным CustomerInfo), но по крайней мере мне гарантирована справочная информация.

Есть ли какой-нибудь другой шаблон или элемент структуры, который я могу использовать, чтобы сделать этот сценарий / реализацию "чище"?

Причина, по которой я спрашиваю, заключается в том, что, хотя мы могли бы просто сказать, что в Northwind ВСЕГДА возвращать полный CustomerDTO, это может хорошо работать в упрощенной ситуации Northwind. В моем случае у меня есть объект, который имеет 25-50 полей, которые являются данными типа ссылки / поиска. Некоторые из них более важны для загрузки, чем другие в различных ситуациях, но я хотел бы иметь как можно меньше определений этих ссылочных типов (чтобы я не попал в «адскую область обслуживания DTO»).

Мнения? Обратная связь? Комментарии?

Спасибо!

Ответы [ 7 ]

2 голосов
/ 18 сентября 2009

Веб-сервис API рекламы продуктов Amazon - хороший пример той же проблемы, с которой вы столкнулись.

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

Наличие разных DTO - хорошая техника, если, как вы говорите, вам не нужен болтливый интерфейс.

2 голосов
/ 09 июля 2009

Мы находимся в одной точке принятия решения по нашему проекту. На данный момент мы решили создать три уровня DTO для обработки Thing: SimpleThing, ComplexThing и FullThing. Мы не знаем, как это сработает для нас, так что это еще не ответ, основанный на реальности.

Одна вещь, которая меня интересует, - можем ли мы узнать, что наши услуги разработаны на «неправильном» уровне. Например, есть ли когда-нибудь случай, когда мы должны разрушить FullThing и только передать SimpleThing? Если мы это сделаем, значит ли это, что мы неправильно поместили некоторую бизнес-логику на слишком высокий уровень?

1 голос
/ 22 сентября 2009

Я обычно встраиваю ленивую загрузку в свои сложные веб-сервисы (то есть веб-сервисы, которые отправляют / получают сущности). Если у Person есть свойство Father (также Person), я отправляю только идентификатор для Father вместо вложенного объекта, тогда я просто проверяю, есть ли у моего веб-сервиса операция, которая может принимать идентификатор и отвечать соответствующей сущностью Person , Затем клиент может перезвонить веб-службе, если хочет использовать свойство Father.

Я также подробно остановился на этом, чтобы пакетирование могло произойти. Если операция отправляет обратно 5 человек, то если к какой-либо из этих личностей обращаются к свойству «Отец», то для всех 5 отцов делается запрос с их идентификаторами. Это помогает уменьшить общительность веб-службы.

1 голос
/ 25 июля 2009

Еще одна возможность - относиться к объектам как к сумкам с недвижимостью Укажите свойства, которые вы хотите при запросе, и получите те свойства, которые вам нужны.

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

1 голос
/ 10 июля 2009

Мы столкнулись с этой проблемой и в объектно-реляционном отображении. Бывают ситуации, когда нам нужен полный объект, а в других - ссылка на него.

Сложность состоит в том, что, запуская сериализацию в сами классы, шаблон datacontract реализует идею, что существует только один правильный способ для сериализации объекта. Но существует множество сценариев, в которых вы можете частично сериализовать класс и / или его дочерние объекты.

Обычно это означает, что вам нужно иметь несколько DTO для каждого класса. Например, FullCustomerDTO и CustomerReferenceDTO. Затем необходимо создать способы сопоставления различных DTO с объектом домена Customer.

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

1 голос
/ 08 июля 2009

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

Я уплачиваю свой Контракт с данными, чтобы он содержал наиболее часто используемые поля элементов справочных данных. Это должно работать для большинства потребителей. Если предоставленных данных недостаточно для данного потребителя, у них будет возможность запросить отдельный сервис, чтобы получить полную информацию о конкретной ссылочной сущности (например, Валюта, Состояние и т. Д.). Для простых поисков, которые на самом деле являются парами ключ / значение, мы будем обрабатывать их с помощью общего контракта данных пары ключ / значение. Я мог бы даже использовать атрибут KnownType для своих более специализированных пар ключ / значение.

[DataContract]
public OrderDTO
{
    [DataMember(Required)]
    public CustomerDTO Customer;

    //in this case, I think consumers will need currency data, 
    //so I pass back a full currency item
    [DataMember(Required)]
    public Currency Currency; 

    //in this case, I think consumers are not likely to need full StateRegion data, 
    //so I pass back a "reference" to it
    //User's can call a separate service method to get full details if needed, or 
    [DataMember(Required)]
    public KeyValuePair ShipToStateRegion;

    //etc..
}


[DataContract]
[KnownType(Currency)]
public KeyValuePair
{
    [DataMember(Required)]
    public string Key;

    [DataMember(Required)]
    public string Value;

    //enum consisting of all possible reference types, 
    //such as "Currency", "StateRegion", "Country", etc.
    [DataMember(Required)]
    public ReferenceType ReferenceType; 
}


[DataContract]
public Currency : KeyValuePair
{
    [DataMember(Required)]
    public decimal ExchangeRate;

    [DataMember(Required)]
    public DateTime ExchangeRateAsOfDate;
}


[DataContract]
public CustomerDTO 
{
    [DataMember(Required)]
    public string CustomerID;

    [DataMember(Required)]
    public string Name;

    //etc....
}

Мысли? Мнения? Комментарии?

1 голос
/ 17 июня 2009

Мне кажется, это сложное решение. Почему бы просто не указать поле идентификатора клиента в классе OrderDTO, а затем позволить приложению решить во время выполнения, нужны ли ему данные клиента. Так как он имеет идентификатор клиента, он может опустить данные, когда он примет такое решение.

...