Search code examples
entity-frameworkodatabreeze

Breeze JS - Repository with EFContextProvider, enabling/disabling OData filtering


I'm looking to implement a repository pattern with breeze EFContextProvider. In this repository, I would expose a method to query the DB using OData filtering... just as breeze behaves by default. I would also want to expose a method that would ignore OData filtering, and return a list of elements as if it was the default EF Context.

So, to sum up, my idea would be to try to do something like this:

public class RepositoryBaseEntity<T> : IRepository<T> where T : class
{
        protected Breeze.WebApi.DataModelContainer _context;

        public RepositoryBaseEntity(Breeze.WebApi.EFContextProvider<DataModelContainer> context)
        {
            _context = context;
        }

        /// <summary>
        /// Gets all elements, ignoring OData filtering
        /// </summary>
        /// <returns>All elements, or null if none exists</returns>
        public IEnumerable<T> GetAll()
        {            
            // disable OData filtering in Breeze.WebApi.EFContextProvider
            return _context.Context.Set<T>();
        }


        /// <summary>
        /// Apply ODataFilters and get elements. Useful for Web API controllers
        /// </summary>
        /// <returns></returns>
        public IEnumerable<T> ApplyODataFiltersAndGet()
        {
            // enable OData filtering in Breeze.WebApi.EFContextProvider
            return _context.Context.Set<T>();
        }

}

I've been taking a look at Breeze EFContextProvider, and there doesn't seem to be a way of disabling OData filtering.

I've though about maybe using the plain old Entity Framework DataModelContainer when I don't want OData filtering, and using Breeze EFContextProvider wrapper when I do want OData filtering... but using this approach I would have two EF contexts... and that's something i want to avoid... in the past in some other projects we've had some problems using more than one EF contexts.

So, you guys see any way of doing this? Thanks!


Solution

  • The OData filtering is actually applied by WebApi prior to executing and JSON-serializing the result. The EFContextProvider provides the initial query, but it does not apply the OData filter because it doesn't know anything about OData.

    To control the filtering in WebApi, add an ODataQueryOptions parameter to your WebApi controller methods. This prevents WebApi from applying the filtering, and allows you to do it instead:

    public IEnumerable<Customer> Customers(ODataQueryOptions options)
    {      
        if (youWantToApplyFilters)
        {
            return repository.ApplyODataFiltersAndGet(options);
        }
        else
        {
            return repository.GetAll();
        }
    }
    

    Then, in your repository,

    /// <summary>
    /// Apply ODataFilters and get elements. Useful for Web API controllers
    /// </summary>
    /// <returns></returns>
    public IEnumerable<T> ApplyODataFiltersAndGet(ODataQueryOptions options)
    {
        var set = _context.Context.Set<T>();
        return options.ApplyTo(set).Cast<T>();
    }
    

    Note that ODataQueryOptions is in System.Web.Http.OData.Query, which means that your repository would be WebApi-specific. If you don't like that, you can move the filtering out of the repository and closer to the controller, or you can pull apart the ODataQueryOptions and put the filtering parameters in your own object (but then you'd have to apply them to the query yourself).