Mar 16, 2010

Specification Pattern with Func<>

Specification is a pattern (Evans/Fowler) that can be used to apply rules for your domain entities:

Create a specification that is able to tell if a candidate object matches some criteria. The specification has a method isSatisfiedBy (anObject) : Boolean that returns "true" if all criteria are met by anObject.

It defines an interface like

public interface ISpecification

{

    bool IsSatisfiedBy<T>(T candidate);

 

    ISpecification And(ISpecification other);

 

    ISpecification Or(ISpecification other);

 

    ISpecification Not();

}

where IsSatisfiedBy() wraps the business logic (not contained in the entity as OO would suggest).

That allows to write business logic code like

price.And(seats).And(slow.Not())

My car specification:

public class CarSpecification : Specifications.CompositeSpecification

{

    public Func<Car, bool> IsSatisfiedFunction { get; set; }

 

    public CarSpecification(Func<Car, bool> isSatisfiedFunction)

    {

        this.IsSatisfiedFunction = isSatisfiedFunction;

    }

 

    public override bool IsSatisfiedBy<T>(T candidate)

    {

        if (!(candidate is Car))

        {

            throw new ArgumentException("must pass Car entity", "candidate");

        }

 

        if (this.IsSatisfiedFunction != null)

        {

            return this.IsSatisfiedFunction(candidate as Car);           

        }

        return false;

    }

}

The whole code:

public partial class MainWindow : Window

{

    private IList<Car> cars;

    private CarSpecification price = new CarSpecification(c => c.Price <= 40000);

    private CarSpecification seats = new CarSpecification(c => c.Seats >= 7);

    private CarSpecification slow = new CarSpecification(c => c.HorsePower < 140);

 

    public MainWindow()

    {

        InitializeComponent();

 

        this.cars = ApplyRules(Cars.Get());

        this.DataContext = this.cars;

    }

 

    private IList<Car> ApplyRules(IList<Car> cars)

    {

        ISpecification myCarSpecification = price.And(seats).And(slow.Not());

        return cars.Where(c => myCarSpecification.IsSatisfiedBy<Car>(c)).ToList();

    }

}

Definitively this simple example could be written in other ways. More importantly you evaluate your new car ….

image

Linq in a Generic Data Access Layer with EF4

Introduction

Decoupling a data access layer (DAL) from business or service logic has become mainstream for some time now – not only due to testing (mocking) reasons but also because replacing your ageing data access technology or your database (manufacturer) may be a topic.

The Interface

I’ve created a simple repository pattern (CRUD) kind of interface over the last year or two. The methods of the interface are generic

int Add<T>(T entity);

int Delete<T>(T entity);

int Update<T>(T entity);

IList<T> GetAll<T>();

// and more

The implementation was done with NHibernate 2.1 and recently with Entity Framework 4.0 (EF4).

The Domain Model

I had several domain models and object-relational mapping (ORM) definitions. Here’s a simple model to show things:

image

A blog or facebook like system that stores Entry objects allows for people to add Comments or just say they like it (Liker).

Using Linq 

Linq is a powerful language feature that can be used to submit queries from the layers on top of the DAL. It is data access and database independent because it works on the domain model – so no coupling to a particular technology.

For this reason I provided a Linq entry point to the interface. Shown here is the EF4 implementation:

public IQueryable<T> GetLinq<T>()

{

    ObjectContext context = GetObjectContext();

    return context.CreateObjectSet<T>() as IQueryable<T>;

}

Or even easier with NHibernate and the NHibernate Linq provider:

public IQueryable<T> GetLinq<T>()

{

    return this.Session.Linq<T>();

}

Now you can program statements like

l = databaseContext.GetLinq<Entry>().Where(entry => entry.Title.Length > 5).ToList();

emitting SQLExpress 2008 T-SQL:

image

Or more complex

var result = from x in this.databaseContext.GetLinq<Entry>()

             join y in this.databaseContext.GetLinq<Liker>()

             on x.Id equals y.Entry_FK

             select new { x.Title, y.Posted };

producing

image

Clean and optimized! The above seems to work due to lazy evaluation and loading.

Note that you could use GetAll<T>().Where() kind of code, but this would return all (10000+) records and only filter on the result set – so a performance killer.