Linq, the Specification Pattern and Encapsulation

An entry about linq Publication date 12. July 2008 15:08

Nicholas Blumhardt (author of Autofac) recently wrote about how Linq can significantly simplify the implementation of the Specification Pattern. He covered the topic excellently, so I won’t regurgitate it here; instead I suggest you go read his post before reading this one.

Done? Cool. One of the downsides Nicholas mentions, is how using the specification pattern can, to a certain degree, break the encapsulation of entities in the domain model.

Disclaimer: Consider this post as a proof of concept. Whether or not the ideas presented here within actually represents something viable, is yet to be seen.

In his Loan class, he has a method IsOverdue:

public bool IsOverdue()
{
    return new OverdueLoanSpecification().IsSatisfiedBy(this);
}

 

Now, imagine we have a web application that uses this method to display either a red or green flag next to each row in a table of loans:

<% foreach (Loan loan in this.ViewData) {%>
    <tr>
        <td>
            <%= loan.IsOverdue() ? 
                Html.Image("~/Content/Icons/red_flag.png") : 
                Html.Image("~/Content/Icons/green_flag.png") %>
        </td>
        <td><%= loan.Book.Title %></td>
        <td><%= loan.DateBorrowed %></td>
        <td><%= loan.DateDue %></td>
        <td><%= loan.DateReturned %></td>
    </tr>        
<%}%>

 

Somewhere else in this application, there might be a method that needs to get all the overdue books from the repository (for some other purpose). There, we might see the following code:

var specification = new OverdueLoanSpecification();
var overdueLoans = dataContext.FindBySpecification(specification);

 

What happened here, is that we broke the encapsulation of the Loan class. What would have been preferable, is this:

var overdueLoans = from loan in loanRepository where loan.IsOverdue() select loan;

 

Such a query has a major problem though: It cannot be executed against a database, because the database will have no idea what IsOverdue means. More precisely, the ORM (in my case Linq to Sql) will have no idea how to translate IsOverdue into SQL. But maybe we can help it? What if we hijack the query expression before it is passed to the ORM, and replace the IsOverdue method call with the specification directly?

For this to work, we need to define specifications as expressions, so that a specification might look something like this:

public class OverdueLoanSpecification : Specification<Loan>
{
    protected override Expression<Func<Loan, bool>> Expression
    {
        get { return loan => loan.DateReturned == null && loan.DateDue > DateTime.Now; }
    }
}

 

Then, if we can just find some way to modify the query expression before executing it, we could just swap out the IsOverdue method call with the expression defined by its specification, so that the query passed to the ORM becomes this:

var overdueLoans = from loan in dataContext.Repository<Loan>() 
                   where loan.DateReturned == null && loan.DateDue > DateTime.Now 
                   select loan;

 

Modifying Expression Trees

There’s an article on MSDN which details exactly how to do this, and reading Tomas Petricek post about dynamically building linq queries is what gave me the idea to go down this road in the first place. Basically, what we need to do is traverse the expression tree and create a new one based on it (because expression trees are immutable), in which we include the necessary replacements. The MSDN article has the source code for an abstract ExpressionVisitor class that we can use to do this: Its overridable VisitMethodCall method will get called for each method call expression found within the query:

protected override Expression VisitMethodCall(MethodCallExpression m)
{
    object[] attributes = m.Method.GetCustomAttributes(typeof (SpecificationAttribute), true);
 
    // process any method calls decorated with the Specification attribute
    if (attributes.Length > 0)
    {
        SpecificationAttribute specificationAttribute = (SpecificationAttribute) attrs[0];
 
        // create an instance of the specification
        ISpecificationExpression specification = (ISpecificationExpression)Activator.CreateInstance(specificationAttribute.Type);
 
        // and get the expression
        LambdaExpression lambda = (LambdaExpression)specification.Expression;
 
        // we need to replace the argument of the function within the expression with the 
        // reference to the one that is currently in scope
        Dictionary<ParameterExpression, Expression> replaceVars = 
            new Dictionary<ParameterExpression, Expression>{{lambda.Parameters[0], m.Object}};
 
        return new SpecificationExpressionStrategy(replaceVars).Visit(lambda.Body);
    }
 
    return base.VisitMethodCall(m);
}

 

One of the MethodCallExpressions in our query will be the IsOverdue method. However, we don’t really have any way of distinguishing this method call from any other – so I’ve introduced a SpecificationAttribute. When we find any method that is decorated with this attribute, we create a new instance of its associated specification and replace the MethodCallExpression with the one defined by the specification. So for instance, our IsOverdue method would now look like this:

[Specification(typeof(OverdueLoanSpecification))]
public bool IsOverdue()
{
    return new OverdueLoanSpecification().IsSatisfiedBy(this);
}

 

When we execute the following code

var overdueLoans = from loan in dataContext.Repository<Loan>() where loan.IsOverdue() select loan;

 

we can see that the expression tree has been modified, replacing the IsOverdue call with the specification expression

Query for overdue loans

A Bonus: Composite Specifications

Okay, so at this point you might argue that having to go through all these hoops might not be worth it just to regain a fraction of encapsulation, and I’d be inclined to agree, especially when you consider the limitations this implementation imposes (we’ll discuss a few of those in a bit). However, encapsulation is not the only win here. Normally, when implementing the specification pattern, you also end up having to implement support for composite specifications, which can be tricky, and the resulting syntax can be verbose and error-prone. By having hidden the actual specifications totally from the client however, we can now leverage Linq fully and get support for composite specifications implicitly. For instance, we can just write a query such as

var overdueLoans = from loan in dataContext.Repository<Loan>() 
                   where loan.Book.IsOnWaitingList() && loan.IsOverdue() 
                   select loan;

 

and under the covers, the IsOnWaitingList and IsOverdue specifications will be used to inject the appropriate criteria into it transparently. And this is just a simple example; we can use joins, groupings and and all of the advanced Linq features without having to write some complicated specification composition API to support it.

Dangers and Limitations

Unfortunately, there are some issues imposed by the specification pattern implementation I’ve introduced here. First of all, there can be some ambiguity in how the code reads. From the code, it looks as if the IsOverdue method will be called, but in reality it might never be – so if there’s a discrepancy between the specification attribute and the actual implementation of the method, then the code will exhibit different behaviours depending on the call context. Having the appropriate unit tests can safeguard against this, however, so I’m not that concerned about it; but its definitively something to be aware of.

As for limitations; we can only use simple expressions that are convertible to SQL to define a specification in this manner. Specifications that need to access data that is not readily available through the candidate type of the specification will be hard to implement, as will parameterized specifications. I have some ideas on how to solve some these issues, at least partially, so look out for a follow-up post on this soon. Until then, I will hold off posting the source code of the implementation that I’ve been talking about in this post, as I’m not quite confident in sharing it in its current state :)

Currently rated 4.6 by 9 people

  • Currently 4.555555/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Comments

Powered by BlogEngine.NET 1.4.5.0

Welcome!

My name is Fredrik Kalseth, and this is my blog - thanks for visiting! I am fortunate enough to work with what I love for a living, and this blog is essentially the biproduct of that.

I work as a senior consultant for Capgemini, and am also an active participant in the Norwegian .NET community, as an avid attendee but also as a speaker (most recently at NNUG and MSDN Live).

As a developer, I have a wide circle of interest. My primary passion is for agile, test-driven development, with focus on best practices and clean code. That said, I also love to work on the frontend, especially with web development.

On Twitter? My handle is fkalseth. On LinkedIn? I`m there too.

Disclaimer

This is a personal blog; any opinions expressed here are my own and do not necessarily reflect those of my employer. All content herein is my own original creation, and as such is protected by copyright law. Unless otherwise stated, all source code posted on this blog is freely usable under the Microsoft Permissive License.

What Readers Talk About

Comment RSS