Living in the Tech Avalanche Generation

A practitioner’s introspective on technology

Entity Framework and the Specification Pattern

A while back I posted a small framework for working with LINQ To SQL. This small set of libraries included a Repository pattern, coupled with the Specification Pattern and Fetching Strategies. In more recent times I decided that LINQ To SQL and the Entity Framework were just too close to warrant the investment in learning, understanding and using both, so to that end I decided to work those previous libraries into shape and refactor them for support of both OR/M products.

First up in this effort I chose to start with the refactor of the Specification interface and class implementation and that will be the item under discussion in this post.

Recently I remarked that the Entity Framework did not support Expression.Invoke() which made combining Specifications to form .Or and .And Specifications in the current version of the library unusable. After some discussion and comments from that previous post and some further investigation, I discovered an alternative that allowed removing the reliance on Invoking Expressions and enabled rewriting the .Or and .And behaviours of the Expression<T> via the magic of some utility classes with some very handy extension methods. Please take a look at Colin Meek’s post that explains and demonstrates the ‘rewriting’ solution and also recently pointed out that the Entity Framework Extensions library includes a way to resolve this issue, however I chose to utilise the other solution so my library did not form a dependency on the extensions library (for the moment).

the OLD Code:

   1: private class OrSpecification : Specification<T>
   2: {
   3:     private readonly ISpecification<T> left;
   4:     private readonly ISpecification<T> right;
   5:     public OrSpecification(ISpecification<T> left,ISpecification<T> right)
   6:     {
   7:         this.left = left;
   8:         this.right = right;
   9:
  10:         this._evalFunc =
  11:             (Func<T, bool>)Func<T, bool>.Combine
  12:             (left.EvalPredicate.Compile(),
  13:             right.EvalPredicate.Compile());
  14:
  15:         ParameterExpression parameter =
  16:             Expression.Parameter(typeof(T), “p”);
  17:         var invokedExpression =
  18:             Expression.Invoke(left.EvalPredicate,
  19:                 right.EvalPredicate.Parameters.Cast<Expression>());
  20:         _evalPredicate =
  21:             Expression.Lambda<Func<T, bool>>
  22:             (Expression.Or(right.EvalPredicate.Body,
  23:             invokedExpression), right.EvalPredicate.Parameters);
  24:     }
  25:     public override bool Matches(T entity)
  26:     {
  27:         return EvalPredicate.Compile().Invoke(entity);
  28:     }
  29: }

Line 18 is the offending line of code.

My NEW Code:

   1: private class OrSpecification : Specification<T>
   2: {
   3:     private readonly ISpecification<T> left;
   4:     private readonly ISpecification<T> right;
   5:     public OrSpecification(ISpecification<T> left,ISpecification<T> right)
   6:     {
   7:         this.left = left;
   8:         this.right = right;
   9:
  10:         this._evalFunc =
  11:             (Func<T, bool>)Func<T, bool>.Combine
  12:             (left.EvalPredicate.Compile(),
  13:             right.EvalPredicate.Compile());
  14:
  15:         _evalPredicate = left.EvalPredicate.Or(right.EvalPredicate);
  16:     }
  17:     public override bool Matches(T entity)
  18:     {
  19:         return EvalPredicate.Compile().Invoke(entity);
  20:     }
  21: }

In short, the extension methods in Colin’s post will kick in and rewrite the behaviour of the .And and .Or method avoiding the need to call Invoke(). This method of composing or ‘rewriting’ as Colin put’s it, also requires a copy of the ExpressionVisitor class which is internal to the Entity Framework. You can find a copy of the ExpressionVisitor here on the wayward blog.

So now I can use my specifications with the Entity Framework! For example if I wish to query my venerable Northwind database and ask for all the products that are now discontinued that are part of existing orders from customers in either Germany and the USA, I can write the following code:

   1: [Test()]
   2: public void RefineCombinedSpecifications()
   3: {
   4:     Specification<Customer> german_customer_spec =
   5:         new Specification<Customer>(c => c.Country == “Germany”);
   6:
   7:     Specification<Customer> us_customer_spec =
   8:         new Specification<Customer>(c => c.Country == “Usa”);
   9:
  10:     Specification<Product> ords_with_discontinued_prods =
  11:         new Specification<Product>(p => p is DiscontinuedProduct);
  12:
  13:     var comb_country_spec = (german_customer_spec | us_customer_spec);
  14:
  15:     using (var ctx = new NorthwindEntities())
  16:     {
  17:         var discontinued_products_on_order =
  18:             (ObjectQuery<Product>)
  19:             (from p in ctx.Products
  20:             .Where(ords_with_discontinued_prods.EvalPredicate)
  21:             from od in ctx.OrderDetails
  22:             from o in ctx.Orders
  23:             from c in ctx.Customers
  24:             .Where(comb_country_spec.EvalPredicate)
  25:             where od.ProductID == p.ProductID &&
  26:                   o.OrderID == od.OrderID &&
  27:                   c.CustomerID == o.Customer.CustomerID
  28:             select p).Distinct();
  29:
  30:         Console.WriteLine(discontinued_products_on_order.ToTraceString());
  31:
  32:         foreach (var product in discontinued_products_on_order)
  33:         {
  34:             Console.WriteLine(“The product ID is {0} with a name of {1}”,
  35:                 product.ProductID, product.ProductName);
  36:         }
  37:     }
  38:
  39:     Console.ReadLine();
  40: }

What’s the benefit you ask? Well the specification class offers me both equality testing (check out the matches method in the download), dynamic querying and and injection as demonstrated in the Repository pattern as here. Next up I will look at flipping open the Repository pattern so it supports LINQ To SQL and the Entity Framework and when the Repository and the Fetching Strategies have been refactored I will post a completely updated version.

Share/Save/Bookmark

2 Comments so far

  1. [...] thought it might be useful to include the entire code base from this previous post with the change to the Specification Pattern alone at this stage, in case anyone wanted to see the [...]

  2. [...] I have also recently posted about a new version of my implementation of the Specification Pattern for Entity Framework that enables the use of that pattern to build dynamic queries and test Entities for equality. [...]

Leave a reply

Creative Commons Attribution-ShareAlike 2.5 Australia
Creative Commons Attribution-ShareAlike 2.5 Australia