【问题标题】:How to filter an odata $expand query in a Web-Api controller如何在 Web-Api 控制器中过滤 odata $expand 查询
【发布时间】:2015-05-12 21:00:34
【问题描述】:

我有两个模型。产品型号:

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public decimal Price { get; set; }

    public virtual ICollection<Categories> Categories { get; set; }
}

还有一个类别模型:

public class Categories
{
    public int Id { get; set; }
    public string Name { get; set; }
    public bool IsPublic { get; set; }

    public virtual Product Products { get; set; }
}

如您所见,模型之间存在关系。一个产品可以有多个类别。我可以使用http://localhost/Products?$expand=Categories 查询模型。

但是,我想在返回类别之前对其进行过滤。主要目标是避免api使用者可以查询IsPublic设置为false的类别。如何在 Web API 控制器中存档?

我的第一次尝试没有成功,因为我需要一个IQueryable&lt;Product&gt;,它返回一个IQueryable&lt;Categories&gt;

        [HttpGet]
        [EnableQuery]
        public IQueryable<Product> Get(ODataQueryOptions<Product> odataQueryOptions)
        {
            if (odataQueryOptions.SelectExpand.RawExpand == "Categories")
            {
                var p = db.Products.First();
                var result = db.Entry(p).Collection(x => x.Categories).Query().Where(x => x.IsPublic == true).AsQueryable();
                return result;
            }
            else
            {
                return db.Products;
            }
        }

基本上我的问题是:在 LINQ 中编写类似 OData 的 $expand 查询的正确方法是什么?如果这是不可能的,我还能如何过滤扩展的导航属性?

【问题讨论】:

  • 不确定您是否仍然需要这个,但我遇到了同样的问题并提出了一个“解决方案”,我已将其发布为我的own question 关于此问题的答案。它可能会帮助您或任何来这里寻找解决方案的人。

标签: entity-framework odata asp.net-web-api asp.net-web-api2


【解决方案1】:

EF 不允许过滤包含的属性。 (这是一个高度投票的feature request for EF,但从未实施:Allow filtering for Include extension method

所以,EF 不支持它。所以我只能为你提供这两个技巧:

  • 在数据库中创建过滤视图,并将其映射到 EF 中的不同实体。这是有效的,因为过滤将在服务器中进行。
  • 在控制器的代码中,将查询投影到一个新类,过滤相关的集合(使用Select(x=&gt; new ...)),并使用.AsQueryable扩展方法制作这个投影结果IQueryable。通过这种方式,您将返回一个新的可查询对象,其中包含根据需要过滤的相关实体。这样比较低效:它需要从数据库服务器恢复整个相关集合,在控制器的方法中对其进行过滤,并将其转换为可查询的

显然,第一个选项是“最佳 hack”。我认为不幸的是没有更好的解决方案。也许还有其他一些技巧,在服务器上使用 TVF 或类似的东西。

【讨论】:

  • 感谢您澄清这一点。希望这个功能很快就会进入 ef。对于您的第一个解决方案,是否可以声明动态视图?例如,对于已登录的用户,应显示类别,对于未登录的用户不?对于您的第二个示例,您能否详细举例说明如何在 web api 中执行此操作?我试过了,但是当 web api 尝试序列化结果时总是出错。
  • 最接近您的“动态视图”概念的是 TVF。它对 Code First 模型的支持很差,并且仅在最新版本中(我认为是 6.1 形式)。如果您的模型是图表,它有更好的支持。谷歌“EF TVF”了解更多信息。您的业​​务逻辑应选择将哪个参数传递给 TVF。对于第二个技巧,考虑到一旦您必须使用Include 进行原始查询。然后您必须将其具体化(例如使用ToList),然后使用Select 进行投影,以便这是LINQ to Objects 而不是LINQ to Entities。然后将其作为可查询返回。
  • 链接已断开,用户语音已关闭。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-09-09
  • 2015-11-29
  • 1970-01-01
  • 2016-08-31
  • 2015-01-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多