Why are there missing client-side results when using OData options with Entity Framework DBContext?

六眼飞鱼酱① 提交于 2019-12-20 06:20:05

问题


OData and Entity Framework are suppose to work well together, in that OData options will be passed to the EF db context to filter queries - ie. return only the number of records requested from the server as not to inflate the payload rather than all the records then filter.

Given the following URL path:

/api/Users?$top=10&$skip=10

Given the following controller action:

    [Queryable(AllowedQueryOptions = AllowedQueryOptions.All)]
    public IEnumerable<USER> Get(ODataQueryOptions<USER> options)
    {
        var dbContext = new ATMS.DAL.AtmsContext();
        //var ret = options.ApplyTo(dbContext.USERS).Cast<USER>().ToArray();        // returns 10 rows but client sees 0
        var ret = dbContext.USERS.ToArray();                                        // returns all records, filtered results to client

        return ret;
    }

When using ret = options.ApplyTo(dbContext.USERS).Cast<USER>().ToArray();, from SQL Server Profiler I see that the appropriate query is executed and 10 results are returned from the db through Entity Framework.

An array of 10 items is returned by ret however the problem is that no data is included in the response to the client:

{
  "odata.metadata":"http://localhost:59337/api/$metadata#Users","value":[

  ]
}

When no skip is specified, the top 10 results are returned - obviously not useful for paging.

When using ret = dbContext.USERS.ToArray(); the top 10 results and skip are properly applied, but only because ALL of the results are returned from the database, and filtering applied thereafter, which is not what I am trying to achieve.

In my WebApiConfig.cs I have config.EnableQuerySupport();.

Adding a PageSize attribute has no effect:

[Queryable(AllowedQueryOptions = AllowedQueryOptions.All, PageSize = 10)]

Returning IQueryable<User> also has no effect.

Returning PageResult<USER> - no change:

    IQueryable results = options.ApplyTo(dbContext.USERS.AsQueryable(), settings);

    return new PageResult<USER>(
        results as IEnumerable<USER>,
        Request.GetNextPageLink(),
        Request.GetInlineCount());

-- More Info --

Using /api/Users?$top=10&$skip=0, if I set a breakpoint at the beginning of the action method and while debugging in Visual Studio I set the Skip.RawValue, and continue execution, I get the 10 results expected:

It appears that somehow the results are being subject to an additional skip, which may be why no results are displayed.

When http://localhost:59337/api/Users?$top=10&$skip=9 is used, the second-last result of page 2 is displayed - only one result.

What am I missing to get this working properly, and has anyone else experienced this?


回答1:


You don't mix and match QueryableAttribute and ODataQueryOptions<T>. Pick one depending on whether you want manual control over applying the query options (ODataQueryOptions<T>) or make it happen automatically (QueryableAttribute).

You have two options,

public IEnumerable<USER> Get(ODataQueryOptions<USER> options)
{
    var dbContext = new ATMS.DAL.AtmsContext();
    var ret = options.ApplyTo(dbContext.USERS).Cast<USER>();
    return ret;
}

or

[Queryable]
public IEnumerable<USER> Get(ODataQueryOptions<USER> options)
{
    var dbContext = new ATMS.DAL.AtmsContext();
    var ret = dbContext.USERS;
    return ret;
}

The reason you are seeing that behavior is that you are applying the query twice, once using ODataQueryOptions<T>.ApplyTo and then again through QueryableAttribute.



来源:https://stackoverflow.com/questions/18130813/why-are-there-missing-client-side-results-when-using-odata-options-with-entity-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!