Entity Framework and the Repository Pattern

When I’ve asked how to unit test Entity Framework, the best answer was “use the Repository pattern to encapsulate your EF code” (thanks Andrew Peters). I recently asked the same thing about RIA Services. Mike Brown responded with the same advice, even going so far as to spend a couple of hours with me on Live Meeting.

Since all you gotta do is implement the Repository Pattern, it should be easy, right? Let’s take a look at a minimalist implementation.

Inject the implementation

To support unit testing, we need to be able to swap out our implementation. At the top level, the consumer of a repository begins a unit of work. So we’ll inject a unit of work factory.

public interface IUnitOfWorkFactory
{
    IUnitOfWork Begin();
}
public class NoteworthyService
{
    private IUnitOfWorkFactory _unitOfWorkFactory;

    public NoteworthyService(IUnitOfWorkFactory unitOfWorkFactory)
    {
        _unitOfWorkFactory = unitOfWorkFactory;
    }
}

Identify the repository

In DDD we create one repository per aggregate root, which is the entity from which you begin the query. In EF, entities exist in a container. So we’ll take two steps to get the repository via the container.

public interface IUnitOfWork : IDisposable
{
    IContainer<TContainer> UsingContainer<TContainer>()
        where TContainer : ObjectContext, new();
}

public interface IContainer<TContainer> : IDisposable
{
    IRepository<TEntity> GetRepository<TEntity>(Func<TContainer, ObjectQuery<TEntity>> repositorySelector)
        where TEntity : EntityObject;
}

Provide a specification

The second half of the Repository Pattern is the Specification. A specification identifies which entities to pull from the repository. In Linq, we use lambdas for that. So a repository should be able to give you back some entities when given a lambda.

public interface IRepository<TEntity>
{
    IQueryable<TEntity> GetSatisfying(Expression<Func<TEntity, bool>> specification);
    void Add(TEntity entity);
}

Query the repository

With those interfaces in place, here’s what a query looks like.

public List<Article> GetArticlesByTopic(string topicName)
{
    using (var unitOfWork = _unitOfWorkFactory.Begin())
    {
        return unitOfWork.UsingContainer<NoteworthyEntities>().GetRepository(container => container.Articles)
            .GetSatisfying(article => article.Topics.Any(topic => topic.TopicName == topicName))
            .ToList();
    }
}

Implement in memory

For unit testing, we implement the repository interfaces using in-memory lists.

public class MemoryUnitOfWorkFactory : IUnitOfWorkFactory
{
    private MemoryUnitOfWork _unitOfWork = new MemoryUnitOfWork();

    public IUnitOfWork Begin()
    {
        return _unitOfWork;
    }
}

public class MemoryUnitOfWork : IUnitOfWork
{
    private Dictionary<Type, object> _containerByType = new Dictionary<Type, object>();

    public IContainer<TContainer> UsingContainer<TContainer>()
        where TContainer : ObjectContext, new()
    {
        object container;
        if (!_containerByType.TryGetValue(typeof(TContainer), out container))
        {
            container = new MemoryContainer<TContainer>();
            _containerByType.Add(typeof(TContainer), container);
        }
        return (IContainer<TContainer>)container;
    }

    public void Dispose()
    {
    }
}

public class MemoryContainer<TContainer> : IContainer<TContainer>
    where TContainer : ObjectContext, new()
{
    private Dictionary<Type, object> _containerByType = new Dictionary<Type, object>();

    public IRepository<TEntity> GetRepository<TEntity>(Func<TContainer, ObjectQuery<TEntity>> repositorySelector)
        where TEntity : EntityObject
    {
        object container;
        if (!_containerByType.TryGetValue(typeof(TEntity), out container))
        {
            container = new MemoryRepository<TEntity>();
            _containerByType.Add(typeof(TEntity), container);
        }
        return (IRepository<TEntity>)container;
    }

    public void Dispose()
    {
    }
}

public class MemoryRepository<TEntity> : IRepository<TEntity>
    where TEntity : EntityObject
{
    private List<TEntity> _entities = new List<TEntity>();

    public IQueryable<TEntity> GetSatisfying(Expression<Func<TEntity, bool>> specification)
    {
        return _entities.Where(specification.Compile()).AsQueryable();
    }

    public void Add(TEntity entity)
    {
        _entities.Add(entity);
    }
}

And here’s what a unit test looks like.

[TestClass]
public class NoteworthyServiceTest
{
    private NoteworthyService _noteworthyService;

    [TestInitialize]
    public void Initialize()
    {
        IUnitOfWorkFactory memory = new MemoryUnitOfWorkFactory();

        IRepository<Article> articlesRepository = memory.Begin()
            .UsingContainer<NoteworthyEntities>()
            .GetRepository(container => container.Articles);
        Topic ddd = new Topic()
        {
            TopicName = "ddd"
        };
        Topic corresopndence = new Topic()
        {
            TopicName = "correspondence"
        };
        Article efRepository = new Article()
        {
            Title = "Entity Framework and the Repository Pattern"
        };
        efRepository.Topics.Add(ddd);
        Article correspondenceLaunch = new Article()
        {
            Title = "Correspondence Launch"
        };
        correspondenceLaunch.Topics.Add(corresopndence);
        Article correspondenceDDD = new Article()
        {
            Title = "Correspondence and DDD"
        };
        correspondenceDDD.Topics.Add(ddd);
        correspondenceDDD.Topics.Add(corresopndence);

        articlesRepository.Add(efRepository);
        articlesRepository.Add(correspondenceLaunch);
        articlesRepository.Add(correspondenceDDD);

        _noteworthyService = new NoteworthyService(memory);
    }

    [TestMethod]
    public void QueryReturnsArticles()
    {
        var articles = _noteworthyService.GetArticlesByTopic("ddd").ToArray();

        Assert.AreEqual("Entity Framework and the Repository Pattern", articles[0].Title);
        Assert.AreEqual("Correspondence and DDD", articles[1].Title);
    }
}

Implement with Entity Framework

Finally, we implement the real thing using Entity Framework.

public class EntityFrameworkUnitOfWorkFactory : IUnitOfWorkFactory
{
    public IUnitOfWork Begin()
    {
        return new EntityFrameworkUnitOfWork();
    }
}

public class EntityFrameworkUnitOfWork : IUnitOfWork
{
    private Dictionary<Type, IDisposable> _containerByType = new Dictionary<Type, IDisposable>();

    public IContainer<TContainer> UsingContainer<TContainer>()
        where TContainer : ObjectContext, new()
    {
        IDisposable container;
        if (!_containerByType.TryGetValue(typeof(TContainer), out container))
        {
            container = new EntityFrameworkContainer<TContainer>();
            _containerByType.Add(typeof(TContainer), container);
        }
        return (IContainer<TContainer>)container;
    }

    public void Dispose()
    {
        foreach (var container in _containerByType.Values)
            container.Dispose();
    }
}

public class EntityFrameworkContainer<TContainer> : IContainer<TContainer>
    where TContainer : ObjectContext, new()
{
    private TContainer _container;

    public EntityFrameworkContainer()
    {
        _container = new TContainer();
    }

    public IRepository<TEntity> GetRepository<TEntity>(Func<TContainer, ObjectQuery<TEntity>> repositorySelector)
        where TEntity : EntityObject
    {
        return new EntityFrameworkRepository<TContainer, TEntity>(_container, repositorySelector(_container));
    }

    public void Dispose()
    {
        _container.Dispose();
    }
}

public class EntityFrameworkRepository<TContainer, TEntity> : IRepository<TEntity>
    where TContainer : ObjectContext, new()
    where TEntity : EntityObject
{
    private TContainer _container;
    private ObjectQuery<TEntity> _objectQuery;

    public EntityFrameworkRepository(TContainer container, ObjectQuery<TEntity> objectQuery)
    {
        _container = container;
        _objectQuery = objectQuery;
    }

    public IQueryable<TEntity> GetSatisfying(Expression<Func<TEntity, bool>> specification)
    {
        return _objectQuery.Where(specification);
    }

    public void Add(TEntity entity)
    {
        _container.AddObject(_objectQuery.Name, entity);
    }
}

Analysis

This is the smallest implementation of the Repository pattern that I could come up with. It is obviously not feature complete. For example, it does not implement Delete, nor does it allow you to specify eager loading with Include. There are other implementations that are bigger, but I doubt that there could be one smaller. Even at this size, this doesn’t qualify as “all you need to do is”.

One benefit of the Repository pattern is supposed to be that it abstracts the persistence mechanism. But this implementation returns EntityObjects, which are a distinctly Entity Framework-ish data type. I could try for a POCO compliant implementation to solve that problem.

Because this implementation requires EntityObjects, it could never work with RIA Services. I would have to write a different Repository implementation to unit test my client code.

And finally, Entity Framework does some things that the in-memory repository does not. My unit tests can’t verify that I’m using EF correctly. For example, Entity Framework does eager loading if I explicitly request it. The in-memory implementation always has all navigation properties populated. Because of this difference, I can’t verify with a unit test that I have included all of the required navigations.

Conclusion

All of this leads me to conclude that the Repository pattern is not the best way to add testability to an untestable framework. The framework needs to be testable from the beginning. If Entity Framework had provided an in-memory implementation for testing, then I could test my use of EF, including eager loading.

By the way, Correspondence does in fact provide an in-memory implementation for unit testing. Please go through the lessons to see what I think a testable framework should look like.

6 Responses to “Entity Framework and the Repository Pattern”

  1. Mickey Says:

    Hello!

    Thank you for your wonderful post!

    I tried it and I loved it!

    My question is: how to migrate this code to Linq-To-SQL correctly?

    I got things working, but I was wondering if I was doing it right.

    1. ObjectContext - was replaced with DataContext
    2. EntityObject - was replaced with class (maybe here I have to validate that DataContext has Table for that class?)
    3. ObjectQuery - was removed (Is there an equivalent for this in Linq-To-SQL?), so IContainer.GetRepository() is now parameterless method.
    4. Repository implementation takes only TContainer as a constructor parameter, and private ObjectQuery _objectQuery; is now private Table _table; that is set in constructor body like this: _table = _container.GetTable();
    5. L2SRepository.GetSatisfying(Expression<Func> specification) - returns _table.Where(specification.Compile()).AsQueryable();
    6. L2SRepository.Add(TEntity entity) - now does: _table.InsertOnSubmit(entity);

    (I hope i didn't miss any changes)

    The code works for me, but I wanted to be shure.

    Thank you!

  2. Michael L Perry Says:

    I'm confused about the removal of the parameter from GetRepository(). How do you identify which table to use?

    Other than that, I get it. It looks like a good port. If you think your changes will help other people test their L2S code, please post it. Send me a link and I'll share it.

  3. Mickey Says:

    Hi, Michael.

    It seems that all the <...> got cleared from my message, so all the generics declaration got lost... I'll try to reconstruct:

    1. ObjectContext - was replaced with DataContext
    2. EntityObject - was replaced with class (maybe here I have to validate that DataContext has Table for that class?)
    3. ObjectQuery - was removed (Is there an equivalent for this in Linq-To-SQL?), so IContainer.GetRepository<TEntity>() is now parameterless method.
    4. Repository implementation takes only TContainer as a constructor parameter, and private ObjectQuery<TEntity> _objectQuery; is now private Table<TEntity> _table; that is set in constructor body like this: _table = _container.GetTable<TEntity>();
    5. L2SRepository.GetSatisfying(Expression<Func<TEntity, bool>> specification) - returns _table.Where(specification.Compile()).AsQueryable();
    6. L2SRepository.Add(TEntity entity) - now does: _table.InsertOnSubmit(entity);

    In L2S the repository is Table<T>, so in GetRepository<TEntity>() there is _context.GetTable<T> - and this is the table (instead of IContainer.GetRepository() I originally wrote IContainer.GetRepository<TEntity>() )

    I revised my code and I changed it a little, so it is now resembles yours for EF very much.

    I can post it (where can I post it so you can download it?)

    I have another question: in implementation of MemoryContainer class you are caching MemoryRepositories, but in EF implementation there are no such caching, why is that?

  4. Michael L Perry Says:

    Ok, that makes more sense. I suggest you check your code into GitHub to share it. Either that or put a zip file on DropBox.

    I look forward to seeing the complete solution.

  5. Mickey Says:

    Hi, Michael

    I have uploaded my solution to GitHub (hopefully correctly as it's my first experience with GetHub), here is the link: http://github.com/mickeyvip/RepositoryPattern

    The solution contains:

    Data.dll:
    SQL Server Express file with some sample data
    Entity Framework model
    LINQ to SQL model

    IEFRepository.dll: one file with interfaces - your code for Entity Framework
    MemoryEFRepository.dll: one file with implementation - your code for Entity Framework
    EFRepository.dll: one file with implementation - your code for Entity Framework

    L2SFRepository.dll: one file with interfaces - for LINQ-to-SQL (almost your code)
    MemoryL2SRepository.dll: one file with implementation - for LINQ-to-SQL (almost your code)
    L2SRepository.dll: one file with implementation - for LINQ-to-SQL (almost your code)

    DataServices.dll:
    EFNoteworthyService.cs - your code for Entity Framework
    L2SNoteworthyService.cs - LINQ-to-SQL (almost your code)

    Repository.Tests.dll:
    EFMemoryTest.cs - tests for Entity Framework, Memory Repository
    EFRepository.cs - tests for Entity Framework, EF Repository
    L2SMemoryTest.cs - tests for LINQ-to-SQL, Memory Repository
    L2SRepository.cs - tests for LINQ-to-SQL, L2S Repository

    Tell me what you think.

  6. Michael L Perry Says:

    Excellent work. Thanks for filling in the holes that I left in the original post. I've posted a follow up:
    http://adventuresinsoftware.com/blog/?p=558

    I just realized that I neglected to answer your question about caching the repositories. The reason that I cache the memory repository is that it maintains state; it holds the list of entities that were added. The EF version maintains state in the ObjectContext, so I don't need to cache its repository.

    Thanks again for the L2S implementation.

Leave a Reply

You must be logged in to post a comment.