【问题标题】:OData V4: Is it possible to only select fields from a parent entity (i.e. navigation property)?OData V4:是否可以仅从父实体(即导航属性)中选择字段?
【发布时间】:2018-08-21 01:04:39
【问题描述】:

OData V3 中,我可以只从父/祖先实体中选择字段,如下所示: http://services.odata.org/V3/Northwind/Northwind.svc/Order_Details(OrderID=10248,ProductID=11)?&$select=产品/类别/类别名称&$expand=产品/类别

该查询仅返回 CategoryName,不包括来自 Order_DetailsProduct 的任何字段。出于性能原因,此行为对我们的应用程序非常重要。在我们不需要时选择所有字段会对查询性能产生重大影响。

似乎没有办法在 OData V4 中完成相同的操作。等效查询返回来自 Order_DetailsProduct 的所有字段 http://services.odata.org/V4/Northwind/Northwind.svc/Order_Details(OrderID=10248,ProductID=11)?$expand=Product($expand=Category($select=CategoryName))

我能得到的最接近的方法是只从每个级别中选择一个字段,这会给我们的代码带来很多复杂性,并且很难确保所有查询(未来和现有)都遵守此规则。

【问题讨论】:

    标签: select odata expand odata-v4


    【解决方案1】:

    这个的语法是:

    http://services.odata.org/V4/Northwind/Northwind.svc/Order_Details(OrderID=10248,ProductID=11)/Product?$expand=Category($select=CategoryName)

    关键是从订单中导航到父产品资源的路径:

    ~/Order_Details(OrderID=10248,ProductID=11)/Product
    

    然后在该资源上应用您的扩展。见4.3 Addressing Entities

    这些规则是递归的,因此可以通过另一个单个实体寻址单个实体,通过单个实体寻址一个集合,甚至通过一个集合来寻址一个集合;示例包括但不限于:

    • 按照从单个实体到另一个相关实体的导航(参见规则:entityNavigationProperty)
      例 14: http://host/service/Products(1)/Supplier

    【讨论】:

    • 这是一种可能的解决方法,在这个人为的示例中有所帮助,但对于我使用过滤器且没有实体 ID 的实际查询没有帮助。我需要的是 OData V3 所具备的能力。不过,答案很有帮助,谢谢。
    • 感谢@SeanJ_2173,在这种情况下,您可以从子表中进行选择,并使用与父表匹配的过滤器。我没有在解决方案中提供它,因为您的问题专门针对 Item 查询而不是集合查询。 :) 您应该发布一个更接近您的实际查询的示例。
    【解决方案2】:

    最简单的解决方案是在您的数据库服务器上创建具有所需架构的视图,并尝试使用过滤器和列名从该数据源获取数据。

    尤其是在面临性能问题时。

    最好的方法是将这个类作为单例注册到你的 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 模型)。

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      我能得到的最接近的方法是从每个级别中选择一个字段, 在我们的代码中引入了很多复杂性 难以确保所有查询(未来和现有)都遵守 这条规则。

      看起来像这样:

      http://services.odata.org/V4/Northwind/Northwind.svc/Order_Details(OrderID=10248,ProductID=11)?$expand=Product($select=Category;$expand=Category($select=CategoryName))&$select=Product

      这里肯定会增加一些复杂性,但在我的情况下这是可以接受的。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-01-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-06-05
        • 2015-09-20
        • 1970-01-01
        相关资源
        最近更新 更多