我有以下 OData 模型
<edmx:Edmx Version="4.0" xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx">
<edmx:DataServices>
<Schema Namespace="ODataIssue.Controllers" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityType Name="Product">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" Nullable="false" />
<Property Name="Description" Type="Edm.String" Nullable="false" />
</EntityType>
<EntityType Name="Category">
<Key>
<PropertyRef Name="Id" />
</Key>
<Property Name="Id" Type="Edm.Int32" Nullable="false" />
<Property Name="Name" Type="Edm.String" Nullable="false" />
<Property Name="Description" Type="Edm.String" Nullable="false" />
<NavigationProperty Name="Products" Type="Collection(ODataIssue.Controllers.Product)" />
</EntityType>
</Schema>
<Schema Namespace="Default" xmlns="http://docs.oasis-open.org/odata/ns/edm">
<EntityContainer Name="Container">
<EntitySet Name="Products" EntityType="ODataIssue.Controllers.Product" />
<EntitySet Name="Categories" EntityType="ODataIssue.Controllers.Category">
<NavigationPropertyBinding Path="Products" Target="Products" />
</EntitySet>
</EntityContainer>
</Schema>
</edmx:DataServices>
</edmx:Edmx>
Run Code Online (Sandbox Code Playgroud)
当对其使用 OData 客户端并运行以下查询时:
var query = container.Categories.Select(c =>
new {
c.Id,
c.Name,
Products = c.Products.Select(p =>
new
{
p.Name,
p.Description
}
)
});
var list = query.ToList();
Run Code Online (Sandbox Code Playgroud)
它生成以下 url http://localhost:5184/odata/Categories?$expand=Products($select=Name),Products($select=Description)&$select=Id,Name。
有没有办法不重复Products($select=而只是生成http://localhost:5184/odata/Categories?$expand=Products($select=Name,Description)&$select=Id,Name?
可用于重现问题的存储库https://github.com/AnderssonPeter/ODataSelectIssue
为了明确意图,OP询问这部分是否:
?$expand=Products($select=Name),Products($select=Description)&$select=Id,Name
Run Code Online (Sandbox Code Playgroud)
可以缩短为仅此(以及如何做到这一点):
?$expand=Products($select=Name,Description)&$select=Id,Name
Run Code Online (Sandbox Code Playgroud)
为了找到答案,我们需要实际查看OData 标准 - URL 约定 - $expand。$expand关于该类别及其使用方法有非常详细的描述。这一段对我们来说很重要:
路径由由正斜杠 (/) 分隔的段组成。段是单值或集合值复杂属性的名称、实例注释或类型转换段,由结构化类型的限定名称组成,该结构化类型派生自前面的路径段标识的类型,以到达在派生的路径段上定义的属性。类型。
路径可以结束于
- 包含该流属性的流属性的名称,
- 星号 (*) 用于展开已识别结构化实例的所有导航属性,可选地后跟 /$ref 以仅展开实体引用,或者
- 用于扩展相关实体的导航属性,可选地后跟类型转换段以仅扩展该派生类型或其子类型之一的相关实体,可选地后跟 /$ref 以仅扩展实体引用。
- 用于扩展一个或多个相关实体的实体值实例注释,可选地后跟一个类型转换段,以仅扩展该派生类型或其子类型之一的相关实体。
用普通人的语言来说:当您只想从对象中选择特定属性时(您尝试仅选择 2 个属性 - , Name)Description,OData 标准将它们视为导航属性,我们必须单独添加它们:
$expand=Products($select=Name),Products($select=Description)
Run Code Online (Sandbox Code Playgroud)
唯一可能的解决方案是获取整个对象,它返回所有数据,并且该查询如下所示:
$expand=Products
Run Code Online (Sandbox Code Playgroud)
所以预期的?$expand=Products($select=Name,Description)实际上不遵循这个标准/会破坏标准的定义〜将是无效的。
需要澄清的是,可以在 OP 已经使用的方法中手动编辑此 URI(显示简单的实现),但它不遵循标准/没有意义:
?$expand=Products($select=Name),Products($select=Description)&$select=Id,Name
Run Code Online (Sandbox Code Playgroud)