Почему моя служба oData (структура сущностей) не позволяет использовать свойства навигации - PullRequest
3 голосов
/ 04 октября 2011

Если я использую свою модель сущности в веб-проекте, я могу нормально перейти к свойствам навигации 1- * 1-0.1 ... но когда я загружаю тот же самый объект через LinqPad в моей службе oData, свойство nav всегда равно null

... я что-то не так делаю? ... как-нибудь включить?

Если я загружаю скрипач и запускаю запрос http://odata.site.com/Service1.svc/usda_FOOD_DES(1001)/usda_ABBREV

... возвращает правильный результат

Спасибо, Стив

Ответы [ 2 ]

4 голосов
/ 23 октября 2011

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

Customers.Where(c => c.ID == 1).Single().Orders

Причина в том, что в отличие от свойств навигации Entity Framework, когда вы обращаетесь к свойству объекта OData, оно автоматически не возвращается к источнику данных и не извлекает какие-либо данные, которых еще нет. Поэтому, когда вы извлекаете сущность из канала OData, по умолчанию она не включает связанные сущности, поэтому вы получаете пустое значение IEnumerable<T> для одного или нескольких или многих для многих навигационных свойств или ноль для свойств навигации для одного объекта.

Вы ожидаете, что вышеприведенный запрос будет переведен на:

HTTP; // odata.sample.com/MyODataFeed.svc/Customers(1)/Orders

Что вернет все ордера, но вместо этого преобразуется в это (чтобы увидеть запрос в LINQPad, нажмите кнопку SQL над панелью результатов):

HTTP; // odata.sample.com/MyODataFeed.svc/Customers(1)

Это связано с тем, что .Orders в конце не входит ни в какой метод расширения и поэтому не участвует в создании IQueryable. Поэтому он не отражается в URL-адресе, созданном из запроса, и не включается в набор результатов.

Так как бы вы получили только заказы клиента 1? Вы можете попытаться обойти проблему, используя следующий запрос:

Customers.Where(c => c.ID == 1).Select(a => c.Orders)

Это должно привести к включению свойства .Orders в запрос. К сожалению, .Select(...) без проецирования результата в анонимный метод (т. Е. new { ... }) не допускается и выдает NotSupportedException: The method 'Select' is not supported. Какой позор. Так что насчёт

Customers.Where(c => c.ID == 1).Select(a => new { c.Orders })

Это не дает ожидаемого результата и вместо этого выполняет следующий запрос:

HTTP; // odata.sample.com/MyODataFeed.svc/Customers(1)?$expand=Orders&$select=Orders

Я не понимаю, почему это просто не переводится в / Customers (1) / Orders. В любом случае, он помещает список заказов в ненужный класс-обертку, что может быть довольно раздражающим, но это работает, и это было самое близкое, что я мог получить к получению только содержимого свойства навигации.

Метод, который я предпочитаю, состоит в том, чтобы включить все заказы с каждым клиентом, как показано ниже:

Customers.Expand("Orders").Where(c => c.ID == 1).Single().Orders

Создает следующий запрос:

HTTP; // odata.sample.com/MyODataFeed.svc/Customers(1)?$expand=Orders

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

0 голосов
/ 23 июня 2014

Последняя версия v4 Asp.Net oData от http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/working-with-entity-relations имеет более точное решение с использованием свойств навигации.

Для поддержки URL:

GET /Products(1)/Supplier

Цитата: здесь»- это свойство навигации по типу продукта.В этом случае поставщик ссылается на один элемент, но свойство навигации также может возвращать коллекцию (отношение «один ко многим» или «многие ко многим»).

Для поддержки этого запроса добавьте следующий методк классу ProductsController:

// GET /Products(1)/Supplier
public Supplier GetSupplier([FromODataUri] int key)
{
    Product product = _context.Products.FirstOrDefault(p => p.ID == key);
    if (product == null)
    {
        throw new HttpResponseException(HttpStatusCode.NotFound);
    }
    return product.Supplier;
}

Ключевым параметром является ключ продукта.Метод возвращает связанный объект - в данном случае экземпляр поставщика.Имя метода и имя параметра оба важны.Как правило, если свойство навигации называется «X», вам необходимо добавить метод с именем «GetX».Метод должен принимать параметр с именем «ключ», который соответствует типу данных родительского ключа.

Также важно включить атрибут [FromOdataUri] в параметр ключа.Этот атрибут указывает веб-API использовать синтаксические правила OData, когда он анализирует ключ из URI запроса.

...