Правильный способ вызова вложенного Expand() из.NET OData 4 Client
проблема
В сервисе OData 4 в Web API, как правильно называть вложенные $ расширения из клиента.NET? Мы используем OData Client Generator. Вернемся к предыдущим службам данных WCF со службой OData 3, которые мы могли бы назвать .Expand("Customers/Orders")
, В веб-API с OData 4 мы больше не можем этого делать и получаем следующее, если вы попытаетесь .Expand("Customers/Orders")
:
Запрос, указанный в URI, недопустим. Найден путь, пересекающий несколько навигационных> свойств. Пожалуйста, перефразируйте запрос так, чтобы каждый путь расширения содержал только тип> сегменты и свойства навигации.
Временное решение
Мы можем обойти эту проблему, вызывая функцию расширения так: .Expand("Customers($expand=Orders)")
, В не вложенных сценариях с расширением $ мне нравится поддержка лямбды .Expand(d => d.Customers)
, Есть ли в клиенте.NET OData 4 правильный способ вызова вложенных расширений без неудачной магической строки .Expand("Customers($expand=Orders)")
? Если нет, то будет ли работать более чистый шаблон строк, такой как "Клиенты / Заказы"? Благодарю.
2 ответа
В OData v4 недопустимо расширять несколько уровней, например то, что вы упомянули в вопросе: .Expand("Клиенты / Заказы"). Я не думаю, что клиент будет поддерживать такой API. Вот что в ABNF http://docs.oasis-open.org/odata/odata/v4.0/os/abnf/odata-abnf-construction-rules.txt:
expand = '$expand' EQ expandItem *( COMMA expandItem )
expandItem = STAR [ ref / OPEN levels CLOSE ]
/ expandPath
[ ref [ OPEN expandRefOption *( SEMI expandRefOption ) CLOSE ]
/ count [ OPEN expandCountOption *( SEMI expandCountOption ) CLOSE ]
/ OPEN expandOption *( SEMI expandOption ) CLOSE
]
expandPath = [ qualifiedEntityTypeName "/" ]
*( ( complexProperty / complexColProperty ) "/" [ qualifiedComplexTypeName "/" ] )
navigationProperty
[ "/" qualifiedEntityTypeName ]
Запрос, который вы хотите отправить:
GET http://host/service/Customers/Orders
право?
Согласно протоколу OData:
Чтобы запросить связанные объекты в соответствии с определенным отношением, клиент отправляет запрос GET на URL-адрес запроса исходного объекта, после которого следует косая черта и имя свойства навигации, представляющего отношение.
Таким образом, такой запрос не поддерживается, так как "Заказчики" до "/ Заказы" - это имя набора сущностей, а не одного объекта. Вы можете написать только вложенное расширение, например:
GET http://host/service/Customers(1)/Orders
Что соответствует следующим фрагментам кода с использованием OData V4 Code Generator:
var orders = context.Customers.ByKey(new Dictionary<string, object>() { { "ID", 1 } }).Orders.Execute();
И вам нужно пройти через всех клиентов, чтобы получить все их заказы.
Небольшое расширение для этого:
public static DataServiceQuery<TSource> Expand<TSource,TNavigation,TExpand>(this DataServiceQuery<TSource> dataServiceQuery, Expression<Func<TSource, DataServiceCollection<TNavigation>>> expression, Expression<Func<TNavigation,TExpand>> navigation)
{
var expressionName = (expression.Body as System.Linq.Expressions.MemberExpression).Member.Name;
var navigationName = (navigation.Body as System.Linq.Expressions.MemberExpression).Member.Name;
return dataServiceQuery.Expand($"{expressionName}($expand={navigationName})");
}
Теперь у вас есть intellisense и проверка типов