【问题标题】:System Query Option $filter in OData v4 (canonical functions)OData v4 中的系统查询选项 $filter(规范函数)
【发布时间】:2015-02-18 12:45:44
【问题描述】:

根据本文档:http://docs.oasis-open.org/odata/odata/v4.0/errata02/os/complete/part2-url-conventions/odata-v4.0-errata02-os-part2-url-conventions-complete.html#_Toc406398094 我应该能够通过 $filter 参数查询,例如“$filter=contains(PropertyName, 'SomeValue')”。

当我传递逻辑运算符时(例如: $filter=PropertyName eq 'SomeValue') 它工作正常。但是像 'contains'、'substring'、'endswith'、'startswith' 等函数永远不会起作用 - 将 ODataQueryOptions 应用于 DbSet 的查询结果始终是一个空集。

有什么想法吗?

【问题讨论】:

  • 您能否将GET 请求的控制器方法附加到您要过滤的实体集?

标签: asp.net-web-api filter odata


【解决方案1】:

我终于发现了可能是什么问题,但我不知道如何解决它。

如果我尝试像这样传递参数查询:

http://(...)/People?$filter=SomeProperty eq 'Foo'

在将 OData 查询选项应用于我的查询后,在我的 WebAPI 控制器方法中,即:

IQueryable<People> queryResults = (IQueryable<People>)queryOptions.ApplyTo(query);

在 queryResults 中有一个这样的片段:

WHERE (`Project1`.`SomeProperty` = @p__linq__0) 

一切正常。但是当我这样传递查询时:

http://(...)/People?$filter=contains(SomeProperty, 'Foo')

在 queryResults 中我可以看到:

WHERE (`Project1`.`SomeProperty` LIKE '%p__linq__0%')

而且总是没有结果。 我不知道我是否理解正确,但它似乎正在寻找包含文本 'p__linq__0' 的 SomeProperty 值,而不是寻找包含 p__linq__0 的 value 的值(即 'Foo' )。


感谢您的回复,@QianLi。 我的控制器看起来像这样:

public class PeopleController : ApiController
{
    readonly PeopleContext _context = new PeopleContext();

    public PageResult<People> Get(ODataQueryOptions<People> queryOptions)
    {
        var query = _context.People.OrderBy(x => x.SomeProperty1);
        var queryResults = (IQueryable<People>)queryOptions.ApplyTo(query);
        long cnt = 0;
        if (queryOptions.Count != null)
            cnt = long.Parse(Request.Properties["System.Web.OData.TotalCount"].ToString());

        return new PageResult<People>(queryResults, null, cnt);
    }
}

(此处解释了使用“cnt”的这种奇怪的解决方法:Items count in OData v4 WebAPI response) 但是现在我放弃了使用 Count 并将控制器实现更改为您所描述的内容:

[EnableQuery]
public class PeopleController : ODataController
{
    public IHttpActionResult Get()
    {
        var query = _context.People.OrderBy(x => x.SomeProperty1);
        return Ok(query);
    }
}

它的工作原理和以前一样 - 使用 eqlt 等过滤查询工作正常,contains 根本不起作用.

编辑:我知道!问题可能是使用此修复程序的结果:http://www.nuget.org/packages/Patches.System.Web.OData/5.3.0-datetimefixes 而不是官方 OData 库。但是我非常需要这个 datetimefixes...

【讨论】:

  • 由于您没有发布代码,我不确定是什么问题,我只是在发布的答案中有一个快速实现,并且 $filter 可以正常工作。希望能有所帮助。
  • 谢谢。不幸的是,它仍然不起作用。我发布了我的控制器代码。
  • 控制器应该继承自ODataController而不是ApiController
  • 是的,它现在继承自 ODataController,正如您在我上面的帖子中看到的那样。它仍然无法正常工作......
  • 您是否在返回码中添加了AsQueryable()?那是var query = _context.People.OrderBy(x =&gt; x.SomeProperty1).AsQueryable();
【解决方案2】:

所以您的意思是 $filter=contains(PropertyName, 'SomeValue') 不适用于您的服务?该功能本身可以很好地工作,请尝试使用http://services.odata.org/TripPinWebApiService/People?$filter=contains(FirstName, 'Angel')。如果您显示代码的更多详细信息,它将帮助其他人解决您的问题。您可以前往https://github.com/OData/ODataSamples/tree/master/Scenarios/TripPin 查看 OData V4 示例服务的实现,或前往 http://aspnet.codeplex.com/SourceControl/latest#Samples/WebApi/OData/v4/ODataQueryableSample/ 了解 Queryable 和 $filter 的工作原理。

由于您没有发布您的代码,我不确定是什么问题,我只是快速实现并且 $filter 可以正常工作。希望能有所帮助。

Person的模型类

public class Person
    {
        [Key]
        public String ID { get; set; }

        [Required]
        public String FirstName { get; set; }

        [Required]
        public String LastName { get; set; }

        [Required]
        public int Age { get; set; }

        public String Description { get; set; }
    }

PeopleController.cs

[EnableQuery]
public class PeopleController : ODataController
{
    public IHttpActionResult Get()
    {
        return Ok(DemoDataSources.Instance.People.AsQueryable());
    }
}

WebApiConfig.cs

   public static class WebApiConfig
    {

        public static void Register(HttpConfiguration config)
        {
            config.MapODataServiceRoute("odata", null, GetEdmModel(), new DefaultODataBatchHandler(GlobalConfiguration.DefaultServer));
            config.EnsureInitialized();
        }

        private static IEdmModel GetEdmModel()
        {
            ODataConventionModelBuilder builder = new ODataConventionModelBuilder();
            builder.Namespace = "Demos";
            builder.ContainerName = "DefaultContainer";

            builder.EntitySet<Person>("People");

            var edmModel = builder.GetEdmModel();

            return edmModel;
        }
    }

然后请求可以正常工作http://localhost:21830/People?$filter=contains(Description,'Lorem')

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-06
    • 2015-07-29
    • 1970-01-01
    • 1970-01-01
    • 2016-02-13
    • 2015-04-24
    • 2016-06-25
    • 1970-01-01
    相关资源
    最近更新 更多