Ответ на этот вопрос полностью зависит от модели вашего домена. Совет, который я бы дал, заключается в том, чтобы экономно использовать OData. На самом деле имеет смысл использовать его только в том случае, если объект, который вы помечаете как отдельный объект, не может существовать вне контекста родительского объекта. Из-за этого ограничения я думаю, что варианты использования для хранения OData немногочисленны. Преимущество перед отдельным контроллером состоит в том, что он может иметь больше смысла с архитектурной точки зрения. Однако ваши контроллеры становятся более раздутыми, и это требует больше усилий, чтобы поддерживать ODataRouteAttributes
в ваших методах. Что-то, что не нужно при использовании условной маршрутизации.
Пример руководства по настройке содержания OData объясняет это несколько. Это немного отстает от того, почему вы будете использовать его. Обратите внимание, что у объекта PaymentInstrument
нет внешнего ключа для Account
. Это означает, что нет отдельной таблицы, в которой хранится информация PaymentInstrument
. Вместо этого он сохраняется непосредственно в записи Account
. Тем не менее, он по-прежнему определяется как Collection<T>
, поэтому он, вероятно, хранится как JSON или в нескольких столбцах. Это может не обязательно иметь место, но с точки зрения кода база данных может выглядеть так.
Для дальнейшего объяснения сдерживания OData, скажем, у нас есть модель предметной области ниже.
public class HttpRequest
{
public int Id { get; set; }
public DateTime CreatedOn { get; set; }
public string CreatedBy { get; set; }
public virtual HttpResponse HttpResponse { get; set; }
}
public class HttpResponse
{
public string Content { get; set; }
public DateTime CreatedOn { get; set; }
}
Как видите, класс HttpResponse
не имеет свойства навигации к HttpRequest
. Поэтому нет смысла хотеть звонить на GET odata/HttpResponses
, как мы получаем все HttpResponses
, но не на HttpRequest
, с которыми они связаны. Другими словами, класс HttpResponse
бесполезен без контекста, то есть HttpRequest
, для которого он был создан.
Класс HttpResponse
, не имеющий никакого значения вне контекста HttpRequest
, делает его идеальным кандидатом для хранения OData. Оба класса могут быть сохранены в одной записи в базе данных. И поскольку невозможно выполнить GET / POST / PUT / DELETE без указания идентификатора HttpRequest
, к которому принадлежит HttpResponse
, для класса HttpResponse
нет смысла иметь собственный контроллер.
Теперь вернемся к вашему варианту использования. Я вижу две вероятные модели предметной области.
- Сущности
User
, UserAddress
, Invoice
и InvoiceAddress
.
В этом первом варианте каждый отдельный объект имеет свой собственный назначенный адресный объект. В этом случае использование OData будет иметь смысл, если использовать такой дизайн, поскольку адресные объекты не существуют вне их соответствующих родительских объектов. UserAddress
всегда связан с User
, а InvoiceAddress
всегда связан с Invoice
. Получение единственного объекта UserAddress
не имеет смысла, поскольку при использовании этой модели предметной области не нужно заботиться о том, где находится один адрес. Вместо этого основное внимание уделяется постоянным адресам для этого единственного User
. Также невозможно создать UserAddress
без указания существующего User
. Сущность UserAddress
опирается на сущность User
полностью .
- Сущности
User
, Invoice
, TypedAddress
и Address
.
В этом втором варианте объект Address
является автономным. Он существует отдельно от других объектов. Поскольку адрес сводится к уникальному местоположению на этой планете, он сохраняется только один раз. Другие сущности затем связываются с сущностью Address
через сущность TypedAddress
, где они указывают, какой это адрес по отношению к сущности, связывающейся с ней. Получение единственного Address
имеет смысл при использовании этой модели предметной области. Адресную книгу всей компании можно легко найти, запросив GET odata/Addresses
. Именно здесь сдерживание OData не имеет смысла.
Обратите внимание, что для настройки содержания можно использовать ODataConventionModelBuilder. Поскольку вам не нужно добавлять ContainedAttribute
в ваш класс, это имеет преимущество, заключающееся в том, что вы не загрязняете слой данных ссылкой на библиотеку OData. Я бы порекомендовал этот подход. В вашей ситуации я бы ожидал иметь конфигурацию ниже.
var modelBuilder = new ODataConventionModelBuilder();
modelBuilder
.EntityType<User>()
.ContainsMany(user => user.UserAddresses);
modelBuilder
.EntityType<Invoice>()
.ContainsMany(invoice => invoice.InvoiceAddresses);