using the OData Queryable with a repository?

2020-06-27 02:09发布

I have this repository method:

public IQueryable<TModel> GetAll()
{
    using (var context = new DatabaseContext())
    {
        return context.Set<TModel>().AsQueryable();
    }
}

where TModel is an artist-model.. anyway

And then I have this action in my controller:

// GET api/artist
[Queryable]
public IQueryable<ArtistModel> Get()
{
    return _repo.GetAll().AsQueryable();
}

Now.. if I would change the repository method to return a List and also add .ToList for my result.. then this would work great. But then no matter what OData query comes in.. I would still first execute a "get all query".. turn them into a list and then I would execute my OData query against that list..

Which seems just plain wrong.. what I would like to do is to make sure that the OData query gets executed the same time as I'm trying to fetch data from the database.. so I only get the very specific result matching the query.. and not a huge bunch of data that then later on gets queried..

For now I have the problem with the DbContext getting disposed once outside the using.. but I still need to close the DbContext as well some where, some how..

Any ideas?

2条回答
家丑人穷心不美
2楼-- · 2020-06-27 02:40

You can enable web API queryable through a couple of ways,

  1. Put the [Queryable] attribute on your action. Your action can return one of these - IEnumerable<T>, IQueryable<T>, HttpResponseMessage with the content being an ObjectContent<IQueryable<T>> or ObjectContent<IEnumerable<T>>, Task<IQueryable<T>>, Task<IEnumerable<T>>, Task<HttpResponseMessage>with the same restrictions as earlier.

  2. Enable querying globally by doing configuration.EnableQuerySupport(). This would enable querying for all methods that return an IQueryable<T>.

  3. Use ODataQueryOptions<T> as mentioned here and manually applying the query yourself.

And regarding the DbContext disposal issue, we evaluate the query very late in a lazy fashion - when the formatter is writing the response to the stream. So, you should not dispose the DbContext in your action. Instead, dispose it along with the controller i.e override the controller's Dispose method and dispose it there. Web API takes care of the controllers life time and disposes the controller when the request is done processing. Also, you can use Request.RegisterForDispose method too, to dispose any resources when the request is done processing.

查看更多
可以哭但决不认输i
3楼-- · 2020-06-27 02:41

The latest version of the queryable extension of web api is kind of confusing, since it is so different from previous versions. In the new version you need to either explicitly enable queryable support or use the new query options class. See this

Edit:Some code this since I am now at a desk

public IQueryable<TModel> GetAll(ODataQueryOptions opts)
    {
        var db = _repo.GetAll();
        return (IQueryable<TModel>) opts.ApplyTo(db);
    }
查看更多
登录 后发表回答