Данные по контракту данных WCF и справочные данные?
Запрос обратной связи/варианты/комментарии относительно "наилучшего" шаблона для использования для справочных данных в моих сервисах.
Что я имею в виду под ссылочными данными?
В качестве примера можно использовать 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 (которая является общей парой Key/Value) всегда требуется в CustomerDTO, у меня всегда будет ReferenceInfo. Это дает мне достаточно информации, чтобы позже получить информацию о Клиенте, если это необходимо. Недостатком того, что CustomerDTO требует ReferenceInfo, является то, что он может быть переполнен, когда я получаю полный CustomerDTO (т.е. С заполнением CustomerInfo), но по крайней мере мне гарантируется справочная информация.
Есть ли какой-нибудь другой шаблон или фреймворк, который я могу использовать, чтобы сделать этот сценарий/реализацию "более чистым"?
Причина, по которой я спрашиваю, заключается в том, что, хотя мы могли бы просто сказать в Northwind, чтобы ВСЕГДА вернули полную CustomerDTO, которая может хорошо работать в упрощенной ситуации в Northwind. В моем случае у меня есть объект с 25-50 полями, которые являются ссылочными/поисковыми типами данных. Некоторые из них более важны для загрузки, чем другие, в разных ситуациях, но я хотел бы иметь как можно меньше определений этих ссылочных типов (чтобы я не попадал в "адский аспект DTO" ).
мнения? Обратная связь? Комментарии?
Спасибо!
Ответы
Ответ 1
Мы находимся в том же решении, что и наш проект. На данный момент мы решили создать три уровня DTO для обработки Thing: SimpleThing, ComplexThing и FullThing. Мы не знаем, как это сработает для нас, так что это еще не ответ, основанный на реальности.
Одна вещь, о которой мне интересно, - это узнать, что наши службы разработаны на "неправильном" уровне. Например, есть ли когда-нибудь экземпляр, где мы должны разделить FullThing и пропустить SimpleThing? Если мы это сделаем, значит ли это, что мы неправильно применяем некоторую бизнес-логику на слишком высоком уровне?
Ответ 2
Веб-сервис API рекламной рекламы Amazon - хороший пример той же проблемы, с которой вы сталкиваетесь.
Они используют разные DTO для предоставления абонентам более или менее подробной информации в зависимости от их обстоятельств. Например, существует небольшая группа ответов , большая группа ответов и в средней группе ответа отклика.
Наличие разных DTO является хорошей техникой, если, как вы говорите, вам не нужен чатный интерфейс.
Ответ 3
Мне кажется сложным решением. Почему бы просто не иметь поле идентификатора клиента в классе OrderDTO, а затем позволить приложению решать во время выполнения, нужны ли ему данные клиента. Поскольку он имеет идентификатор клиента, он может вытащить данные, когда он это решит.
Ответ 4
Я решил отказаться от подхода, который я собирался предпринять. Я думаю, что многие из моих первоначальных опасений были связаны с отсутствием требований. Я вроде как ожидал, что это так, но было любопытно посмотреть, как другие могли бы решить эту проблему, чтобы определить, когда загружать определенные данные, а когда нет.
Я сжимаю свой контракт с данными, чтобы содержать наиболее используемые поля элементов опорных данных. Это должно работать для большинства потребителей. Если предоставленных данных недостаточно для данного потребителя, у них будет возможность запросить отдельную службу, чтобы отбросить полную информацию для конкретной ссылочной единицы (например, Валюта, Состояние и т.д.). Для простых поисков, которые действительно являются в основном парами Key/Value, мы будем обрабатывать их с помощью общего контракта данных Key/Value. Я мог бы даже использовать атрибут KnownType для более специализированных пар Key/Value.
[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 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....
}
Мысли? Мнения? Комментарии?
Ответ 5
Мы столкнулись с этой проблемой и в объектно-реляционном сопоставлении. Есть ситуации, когда нам нужен полный объект и другие, где мы хотим получить ссылку на него.
Трудность состоит в том, что, выпекая сериализацию в самих классах, шаблон datacontract обеспечивает идею о том, что существует только один правильный способ сериализации объекта. Но есть много сценариев, где вы можете частично сериализовать класс и/или его дочерние объекты.
Это обычно означает, что для каждого класса необходимо иметь несколько DTO. Например, FullCustomerDTO и CustomerReferenceDTO. Затем вам нужно создать способы сопоставления различных DTO с объектом домена Customer.
Как вы можете себе представить, это тонна работы, большая часть которой очень утомительна.
Ответ 6
Еще одна возможность - рассматривать объекты как имущественные мешки. Укажите нужные свойства при запросе и верните именно те свойства, которые вам нужны.
Изменение свойств, отображаемых в "короткой" версии, не потребует нескольких обращений в оба конца, вы можете получить все свойства для набора за один раз (избегая чат-интерфейсов), и вам не нужно изменять ваши данные или операционные контракты, если вы решите, что вам нужны разные свойства для "короткой" версии.
Ответ 7
Я обычно создаю ленивую загрузку для своих сложных веб-сервисов (т.е. веб-сервисов, отправляющих/получающих объекты). Если у Человека есть свойство Отца (также Лицо), я посылаю только идентификатор Отца вместо вложенного объекта, тогда я просто убеждаюсь, что у моего веб-службы есть операция, которая может принять идентификатор и ответить соответствующим сущностью Person, Затем клиент может вызвать веб-службу, если хочет использовать свойство Отца.
Я также расширил это, так что может произойти пакетная обработка. Если операция отправляет обратно 5 человек, тогда, если к собственности Отца обращаются к кому-либо из этих Лиц, тогда запрос делается для всех 5 Отцов с их идентификаторами. Это помогает снизить уязвимость веб-службы.