I am trying to implement OData in WebApi. I am using the repository pattern and EF5 (in the backend) which is still consistent with all the examples I have found. Here is
Here's some code that demonstrates your requirement.
To achieve the result you need to ensure that the query has been executed (using ToList()
). The most efficient way to do this is to add paging (bonus) and return a PageResult<>
object.
public PageResult<WebPoco> Get(ODataQueryOptions<WebPoco> queryOptions)
{
var data2 = DatabaseData();
//Create a set of ODataQueryOptions for the internal class
ODataModelBuilder modelBuilder = new ODataConventionModelBuilder();
modelBuilder.EntitySet<DatabasePoco>("DatabasePoco");
var context = new ODataQueryContext(
modelBuilder.GetEdmModel(), typeof(DatabasePoco));
var newOptions = new ODataQueryOptions<DatabasePoco>(context, Request);
var t = new ODataValidationSettings() { MaxTop = 25 };
var s = new ODataQuerySettings() { PageSize = 25 };
newOptions.Validate(t);
IEnumerable<DatabasePoco> results =
(IEnumerable<DatabasePoco>)newOptions.ApplyTo(data2, s);
int skip = newOptions.Skip == null ? 0 : newOptions.Skip.Value;
int take = newOptions.Top == null ? 25 : newOptions.Top.Value;
List<DatabasePoco> internalResults = results.Skip(skip).Take(take).ToList();
// map from DatabasePoco to WebPoco here:
List<WebPoco> webResults;
PageResult<WebPoco> page =
new PageResult<WebPoco>(
webResults, Request.GetNextPageLink(), Request.GetInlineCount());
return page;
}
Here's the using statements
using System.Web.Http;
using System.Web.Http.OData;
using System.Web.Http.OData.Builder;
using System.Web.Http.OData.Query;
test classes
public class WebPoco
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
public class DatabasePoco
{
public int id { get; set; }
public string name { get; set; }
public string type { get; set; }
}
and some data for testing
private IQueryable<DatabasePoco> DatabaseData()
{
return (
new DatabasePoco[] {
new DatabasePoco() { id = 1, name = "one", type = "a" },
new DatabasePoco() { id = 2, name = "two", type = "b" },
new DatabasePoco() { id = 3, name = "three", type = "c" },
new DatabasePoco() { id = 4, name = "four", type = "d" },
new DatabasePoco() { id = 5, name = "five", type = "e" },
new DatabasePoco() { id = 6, name = "six", type = "f" },
new DatabasePoco() { id = 7, name = "seven", type = "g" },
new DatabasePoco() { id = 8, name = "eight", type = "h" },
new DatabasePoco() { id = 9, name = "nine", type = "i" }
})
.AsQueryable();
}
If the Queryable you return is via a dbContext.dbSet.Select(x => new Model { Id = x.Id}) mechanism instead of AutoMapper. Then applying conditions on the Queryable can be translated and evaluated by the EF LINQ provider automatically. Otherwise, you're going to have to write a custom LINQ provider which changes the expressions from being expressions based off of Model properties to expressions off of EF_Class properties.