在OData V3中,我只能从父/祖先实体中选择字段,如下所示:http://services.odata.org/V3/Northwind/Northwind.svc/Order_Details(OrderID=10248,ProductID=11)?& $ select = Product / Category / CategoryName&$ expand = Product / Category
该查询仅返回CategoryName,它不包括Order_Details或Product中的任何字段。出于性能原因,此行为对我们的应用程序非常重要。在我们不需要它们时选择所有字段会对查询性能产生重大影响。
在OData V4中似乎没有办法实现相同的目标。等效查询返回Order_Details和Product http://services.odata.org/V4/Northwind/Northwind.svc/Order_Details(OrderID=10248,ProductID=11)中的所有字段?$ expand = Product($ expand = Category($ select = CategoryName))
我能得到的最接近的是从每个级别中选择一个字段,在我们的代码中引入了很多复杂性,并且很难确保所有查询(未来和现有)都遵守此规则。
最简单的解决方案是在数据库服务器上创建具有所需模式的View,并尝试使用过滤器和列名称从此数据源获取数据。
特别是在面对性能问题时。
最好的方法是将此类作为单例注册到IoC
public class InternalODataEdmModelBuilder
{
private readonly ODataConventionModelBuilder _oDataConventionModelBuilder = new ODataConventionModelBuilder();
private IEdmModel _edmModel;
public InternalODataEdmModelBuilder()
{
ODataEntitySetsConfigInternal.Register(_oDataConventionModelBuilder);
}
// cache
public IEdmModel GetEdmModel()
{
return _edmModel ?? (_edmModel = _oDataConventionModelBuilder.GetEdmModel());
}
}
internal static class ODataEntitySetsConfigInternal
{
public static void Register(ODataConventionModelBuilder oDataModelBuilder)
{
if (oDataModelBuilder == null)
{
throw new Exception("'ODataConventionModelBuilderWebApi' cannot be null");
}
oDataModelBuilder.EntitySet<YourView>("YourView").EntityType.HasKey(x => x.YourKey);
}
}
然后在API控制器中注入此注册对象,并从URL构建您的查询,如下所示:
ODataQueryContext queryContext = new ODataQueryContext(_oDataConventionModel, typeof(YourViewEFType), null);
var option = new ODataQueryOptions(queryContext, Request);
var data = option.ApplyTo(data, new ODataQuerySettings { EnsureStableOrdering = false });
然后将数据映射到您的POCO(向公众展示的API EDM模型)。
希望这可以帮助。