问题
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