2

Abstracting the Data Access Layer

Posted in .Net, C#, Development at May 18th, 2009 by Ben / 2 Comments »

This article endeavours to describe how to use the Repository Pattern to abstract and control access (CRUD operations) to a data model locally, through mocks and over-the-wire using the Entity Framework and ADO.Net Data services respectively.

By exposing your Data Access model through a defined interface you can replace your data access implementation to suit your needs whether it be for unit testing or to change the data access frameworks you use.

Background:

Microsoft is pushing the ADO.Net Entity Framework as the ORM of choice going forward.

It’s usually a good idea to get behind Microsoft’s frameworks as you know they will build all sorts of cool utilities and other frameworks on top of them and we all want these goodies. (NOTE: I say usually, because sometimes they cease to support frameworks they’ve pushed before eg. Linq-to-Sql).

The E.F has a number of issues that you will find lots of complaints about on the net, with the most annoying being no support for Persistence Ignorance (i.e. POCOs). However, if you can work around this or are fortunate enough to start a new project where your conceptual model hasn’t been defined yet you might still consider using the E.F.

This article won’t go into the arguments for and against the E.F. and is aimed at people who are happy to head down the E.F. path.

When you use the E.F. you’re next step might be to utilize the RESTful framework they’ve built on top of it called ADO.Net Data Services (formerly Astoria). By simply plugging in your E.F. model you can easily expose portions of your data model over the web via a RESTful nature.

Getting automatic exposure to your data model over http is very exciting due to its simplicity and that universal appeal that any client can interact with your server code.

Let’s get started.

The Repository Pattern:



/// 
/// Generic CRUD Repository operations.
/// 
public interface IRepository : IDisposable
{
    T Single<T>(Expression<Func<T, bool>> whereCondition, params string[] includes);
    Collection<T> Get<T>(Expression<Func<T, bool>> whereCondition, params string[] includes);
    Collection<T> Get<T, TKey>(Expression<Func<T, bool>> whereCondition, Expression<Func<T, TKey>> orderBy, bool ascending, params string[] includes);
    Collection<T> Get<T, TKey>(Expression<Func<T, bool>> whereCondition, Expression<Func<T, TKey>> orderBy, bool ascending, int startRow, int pageLength, out long totalCount, params string[] includes);
    Collection<T> GetAll<T>();
    void Delete<T>(T entity);
    void Add<T>(T entity);
    void SaveChanges();
    bool IsDisposed();
}

First we define the Repository interface. The repository interface exposes a generic set of Create, Read, Update and Delete (CRUD) operations to work against any type of Entity – T.

It’s worth noting that the Get operations take a list of “include” parameters. These “includes” explicitly define which relationship properties to explicitly (eagerly) load when returning the Entity (or collection of Entities) of type T.

For example:


var order = repository.Single<Order>(o => o.OrderID == 10250);

When you call Single on an Order entity the Order entity will be returned; however its Customer property will be null by default.

If you wish to return the Order entity with its Customer relationship eagerly loaded you must specify this explicitly.


var order = repository.Single<Order>(o => o.OrderID == 10250, "Customer");

(NOTE: The IRepository interface has been defined this way for two reasons:

  1. The Entity Framework doesn’t support lazy loading of dependent properties (yet!)
  2. Because we are using the same interface for local access to a data store and also for access across the wire using ADO.Net data service it’s best to explictly know exactly what you are pulling across
    from the underlying datastore for bandwidth and performance reasons.

)

Now that we have a generic Repository interface it’s simply a matter of creating the implementations you require. You can create any implementation to wrap whatever Data Access framework you want, including Linq-to-Sql, Entity Framework, NetTiers, NHibernate, Sonic, your own framework, etc.

For the purposes of this article, I have created two implementations:

  1. An entity framework repository.
  2. An ADO.Net Data Service (.Net Client) repository.

The EntityFrameworkRepository implementation works with a VS2008 generated .EDMX ObjectContext instance and utilizes the Microsoft EFExtensions project to add support for SPROC access.

The DataServiceRepository implementation requires ADO.Net Data Services CTP 1.5 to be installed on your machine to utilize query performance improvements (count) and the INotifyPropertyChanged and INotifyCollectionChanged interface implementations on the client proxy objects to implement change-tracking on the entities.

(NOTE: In the future I hope to create a .Net Data Service (Silverlight Client) repository too.)

Once the desired IRepository implementations have been created you may consider creating an IRepositoryFactory implementation to manage the Repository location and lifecycle operations for you.



    /// 
    /// Factory to return instances of .
    /// 
    public interface IRepositoryFactory
    {
        /// <summary>
        /// Get an instance of <see cref="IRepository"/>
        /// </summary>
        /// <param name="name">the name of the repository to return</param>
        /// <returns>an instance of <see cref="IRepository"/></returns>
        IRepository GetRepository(string name);
    }

Access the EF model in-process:


var repository = repositoryFactory.GetRepository("Northwind_Local");
Orders order = repository.Single<Orders>(o => o.OrderID == 10250);

Or to go over the wire:


var repository = repositoryFactory.GetRepository("Northwind_DataService");
Orders order = repository.Single<Orders>(o => o.OrderID == 10250);

Or to mock out for unit testing:


IRepository mockRepository = MockRepository.GenerateMock<IRepository>();
Expression<Func<Orders,bool>> whereCondition = o => o.OrderID == 3;
mockRepository.Stub(r => r.Single(whereCondition)).Return(new Orders() { OrderID = 3 });
RepositoryFactory.SetRepository("Northwind_Local", mockRepository);

IRepository repository = _repositoryFactory.GetRepository("Northwind_Local");
Orders order = repository.Single(whereCondition);

Where to next:

Download the Repository Pattern VS 2008 SP1 Solution.

Install the ADO.Net Data Services CTP 1.5 installer found under /3rdPartyAssemblies/ADONETDataServices_v15_CTP1.exe in the zip file download.

Then set an environment variable dscodegen_databinding value to 1.
This ensures service reference generation in VS2008 uses CTP version and not the old school version. View the video in this link for more info.

Once you are setup, open up the various unit test classes to see how to utilize the various implementations. The EF model is generated against the Northwind database (included as a file reference).

Reference Links:

Persistence Ignorance
http://blogs.msdn.com/dsimmons/archive/2007/06/02/persistence-ignorance-ok-i-think-i-get-it-now.aspx

Repository Pattern
http://blogs.hibernatingrhinos.com/nhibernate/archive/2008/10/08/the-repository-pattern.aspx

Repository Pattern with EF

Data Access with Repository
http://blogs.microsoft.co.il/blogs/kim/archive/2008/11/12/data-access-with-the-entity-framework.aspx

Testable Data Access with the Repository Pattern
http://blogs.microsoft.co.il/blogs/kim/archive/2008/11/14/testable-data-access-with-the-repository-pattern.aspx

Entity Framework – Some Common Hurdles
http://blogs.microsoft.co.il/blogs/kim/archive/2008/11/17/entity-framework-some-common-hurdles.aspx

ADO.Net Data Services CTP – 1.5

ADO.Net Data Services Blog
http://blogs.msdn.com/astoriateam/default.aspx

Data Binding (ie.implements INotifyPropertyChanged and INotifyCollectionChanged interfaces)
http://blogs.msdn.com/astoriateam/archive/2009/03/21/ado-net-data-services-v1-5-ctp1-data-binding-overview.aspx

Microsoft EFExtensions
http://code.msdn.microsoft.com/EFExtensions

Published in .Net, C#, Development

2 Responses to “Abstracting the Data Access Layer”

  1. July 27th, 2009 at 7:17 am #Ben Clark-Robinson

    An amazing post with code and project. Thank you and will be following this blog closely.

  2. July 27th, 2009 at 8:38 pm #Ben

    Thanks mate. Appreciate it.

Leave a Reply