Avrohom Yisroel
Avrohom Yisroel

Reputation: 9482

Can I intercept Entity Framework when it loads data from the database?

We have a multi-layered application, where all the repositories are based on a (home-grown) GenericRepository base class (where T is an entity in the model), that exposes methods such as GetContext(), GetObjectSet() and so on. We allow the repositories that inherit from this to access the context, as they need to call Include(), as we are passing the data up through a WCF service, so need to load all related entities eagerly.

All of our entities implement an interface that has an Active bool property, and what we want to do is intercept the execution of a query, and filter on the Active property, so that any query only returns entities where this is set to true.

Can this be done? In Lightswitch, which is built on EF, there is an event you can capture that gets fired right down in the depths of the query execution, and allows you to do this sort of filtering. I can't find anything in EF itself that allows this.

Anyone any ideas? Thanks

Upvotes: 0

Views: 898

Answers (2)

Nick Butler
Nick Butler

Reputation: 24433

In EF 5, Include is an extension method on IQueryable, so you can do this:

var query = dbSet.Where( o => o.IsActive ).Include( ... )

That means, you don't have to return a DbSet<T> from your generic repository - it should be ok to return an IQueryable<T>.

If this meets your requirements, you can add a Where clause to your generic repository method:

partial class GenericRepository<T>
{
  public IQueryable<T> Query( bool includeInactive = false )
  {
    return ctx.Set<T>().Where( o => includeInactive || o.IsActive );
  }
}

Upvotes: 1

Corey Adler
Corey Adler

Reputation: 16149

The best way that I can think of doing that would be to have your repository methods take in an Expression (i.e. Expression<Func<T, bool>> predicate). That way you can do all of your queries in the actual repository itself (and thus not allowing client-side code any way of accessing your data layer logic) to which you can add a Where before you return from the repository method to only grab those that are Active.

An example of this style that I've used is the following:

   public IQueryable<T> Grab(Expression<Func<T, bool>> predicate)
   {
     return DbSet.Where(predicate);
   }

Where DbSet is the actual table that you're trying to query. That way you can add .Where(x => x.Active) to the end of it, have it not execute against the database yet (thank you, deferred execution!) and yet still get the exact records that you're looking for.

Upvotes: 1

Related Questions