从.NET OData 4客户端调用嵌套扩展()的正确方法 问题

从.NET OData 4客户端调用嵌套扩展()的正确方法 问题,odata,wcf-data-services,asp.net-web-api,astoria,wcf-data-services-client,Odata,Wcf Data Services,Asp.net Web Api,Astoria,Wcf Data Services Client,在Web API上的OData4服务中,从.NET客户端调用嵌套$expand的正确方法是什么?我们正在使用。回到之前的WCF数据服务和OData 3服务,我们可以调用.Expand(“客户/订单”)。在使用OData 4的Web API中,如果您尝试.Expand(“客户/订单”),我们将无法再这样做并收到以下信息: URI中指定的查询无效。找到一个遍历多个导航>属性的路径。请重新表述查询,使每个展开路径仅包含类型>段和导航属性 变通办法 我们可以通过像这样调用expand来解决这个问题:.e

在Web API上的OData4服务中,从.NET客户端调用嵌套$expand的正确方法是什么?我们正在使用。回到之前的WCF数据服务和OData 3服务,我们可以调用
.Expand(“客户/订单”)
。在使用OData 4的Web API中,如果您尝试
.Expand(“客户/订单”)
,我们将无法再这样做并收到以下信息:

URI中指定的查询无效。找到一个遍历多个导航>属性的路径。请重新表述查询,使每个展开路径仅包含类型>段和导航属性

变通办法
我们可以通过像这样调用expand来解决这个问题:
.expand(“Customers($expand=Orders)”)
。在非嵌套的$expand场景中,我喜欢lambda支持,比如so
.expand(d=>d.Customers)
。在.NET OData 4客户端中,有没有合适的方法来调用嵌套扩展,而不使用不幸的神奇字符串
.Expand(“Customers($Expand=Orders)”)
?如果没有,是否有像“客户/订单”这样更干净的字符串模式可以工作?谢谢。

您要发送的请求是:

GET http://host/service/Customers/Orders
对吧?

根据OData协议:

要根据特定关系请求相关实体,客户端向源实体的请求URL发出GET请求,后跟正斜杠和表示关系的导航属性的名称

因此,不支持此类请求,因为“/Orders”之前的“Customers”是实体集的名称,而不是单个实体的名称。您只能编写嵌套扩展,如:

GET http://host/service/Customers(1)/Orders
它对应于使用OData V4代码生成器的以下代码段:

var orders = context.Customers.ByKey(new Dictionary<string, object>() { { "ID", 1 } }).Orders.Execute();
var orders=context.Customers.ByKey(新字典(){{“ID”,1}}).orders.Execute();

您需要遍历所有客户以获取他们的所有订单。

在OData v4中,扩展多级是无效的,例如您在问题中提到的:。扩展(“客户/订单”)。我认为客户不会支持这样的API。以下是ABNF中的内容:


对此进行了一点扩展:

        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})");
    }
公共静态DataServiceQuery扩展(此DataServiceQuery DataServiceQuery、表达式表达式、表达式导航)
{
var expressionName=(expression.Body作为System.Linq.Expressions.MemberExpression.Member.Name;
var navigationName=(navigation.Body作为System.Linq.Expressions.MemberExpression.Member.Name;
返回dataServiceQuery.Expand($“{expressionName}($Expand={navigationName})”);
}
现在您有了智能感知和类型检查

例如:


db.Container.Expand(c=>c.Customers,customer=>customer.Orders)

@yiu-Ding,很高兴收到您的回复。不过,请你重读我的问题好吗?看来你弄错了主题。当我说扩展时,我的意思是扩展为$expand。@Tan_Jinfu谢谢,这是一个好信息。但它引出了一个问题,“$expand=Customers($expand=Orders)”为什么会在MS实现中工作?此外,还有一个on System.Web.OData.EnableQueryAttribute,它表示获取或设置$expand查询选项的最大扩展深度。要禁用最大扩展深度检查,请将此属性设置为0。因为$expand=Customers($expand=Orders)中的$expand=Orders称为查询选项,而查询选项可以是$filter或另一个$expand,ABNF为:expandOption=expandreOption/select/expand/levelsHow come。虽然此处有明确说明,但它无效:服务器端OData v4的MS实现支持嵌套$expand和$select,但这里的问题是如何使用OData客户端生成器生成的代理构造这样的查询。。。关键是使用Linq select函数选择我们想要匿名类型的特定字段。在OData v3场景中,您可以看到这一点。感谢.NET OData 4客户端的解决方案:。在url中展开(“客户($Expand=Orders)”),您可以这样使用:?$Expand=Customers($Expand=Orders)参考:这是一个很好的答案,但我对这个函数的实际调用方式感到困惑……我发现,这个特定函数用于处理返回+集合+实体的实体上的属性。所以要使用它,您可以执行以下操作:r=container.MyProducts.Expand(p=>p.Categories,category=>category.CategoryType)是的,它用于集合属性中的嵌套对象(或集合)。您也可以像这样使用它:r=container.MyProducts.Expand(p=>p.Customers,customer=>customer.Orders)(如初始问题)
        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})");
    }