Я задал себе тот же вопрос. Мне было интересно, почему следующее вернуло пустую коллекцию:
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(...)
проблематично - оно имеет слабую типизацию, поэтому оно не будет проверяться компилятором (остерегаться орфографических ошибок), не все инструменты рефакторинга тоже будут его реорганизовывать, находя все варианты использования этого свойства. не будет включать эту строку в результаты поиска и т. д.