Episode 1 – Repository with EF Magic Unicorn (CTP 4) 2

This will be the first episode in a series of posts that I hope I’ll be able to write in the next few weeks.

I’m working on a reference architecture for back-end services that use a few of the new technologies in .NET Framework 4 (and some that are still in preview). This first post will be dedicated to showing my implementation of the Repository pattern when using the code-only features of Entity Framework Magic Unicorn Edition (or CTP 4 as it is officially called).

Plumbing

Let’s start by having a look at a generic IRepository interface that I will start off from:

public interface IRepository<TEntity>
    where TEntity : class
{
    TEntity Get(Expression<Func<TEntity, bool>> whereClause);

    IEnumerable<TEntity> List();
    IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> whereClause);

    void Add(TEntity entity);
    void Delete(TEntity entity);
}

This interface could be used for pretty much any ORM or similar data access methodology and ensures us that the data layer is reasonably separated from the rest of the application or service. Using an instance of it might look something like this:

TaskRepository.Add(new Task() { Title = "Do this", Priority = 1 });
TaskRepository.Add(new Task() { Title = "Do that", Priority = 2 });

var highPriorityTasks = TaskRepository.Find(e => e.Priority == 1);

Now, let’s implement this interface using the new code-only API in the Entity Framework CTP 4. It is actually quite straight-forward. I’m building a generic base class that can be used directly, but also supports (and even encourages) deriving from.

/// <summary>
/// Base class for implementing the Repository pattern over an Entity Framework Code Only-based entity
/// </summary>
/// <remarks>Usually you will derive from this class to create an entity-specific repository</remarks>
/// <typeparam name="TEntity">Entity to expose via the Repository</typeparam>
public class RepositoryBase<TEntity> : IRepository<TEntity>
    where TEntity : class
{
    private readonly IDbSet<TEntity> _dbSet;

    public RepositoryBase(DbContext dbContext)
    {
        _dbSet = dbContext.Set<TEntity>();

        if (_dbSet == null)
            throw new InvalidOperationException("Unable to create object set");
    }
    
    /// <summary>
    /// This property can be used by derived classes in order to get access to the underlying DbSet
    /// </summary>
    protected virtual IDbSet<TEntity> Query
    {
        get { return _dbSet; }
    }

    /// <summary>
    /// Return all entities
    /// </summary>
    public virtual IEnumerable<TEntity> List()
    {
        return Query.ToArray(); 
    }

    /// <summary>
    /// Return all entities that match the <c cref="whereClause">whereClause</c>
    /// </summary>
    public virtual IEnumerable<TEntity> Find(Expression<Func<TEntity, bool>> whereClause)
    {
        return Query.Where(whereClause).ToArray();
    }

    /// <summary>
    /// Return the first entity that matches the <c cref="whereClause">whereClause</c>
    /// </summary>
    public virtual TEntity Get(Expression<Func<TEntity, bool>> whereClause)
    {
        return Query.Where(whereClause).FirstOrDefault();
    }

    /// <summary>
    /// Add a new entity to the repository
    /// </summary>
    public virtual void Add(TEntity entity)
    {
        _dbSet.Add(entity);
    }

    /// <summary>
    /// Delete an existing entity from the repository
    /// </summary>
    public virtual void Delete(TEntity entity)
    {
        _dbSet.Remove(entity);
    }
}

And that was pretty much all the plumbing we need! So why don’t we put it to some use?

Let’s use it!

I’m working with a very simple domain model (that will be expanded a bit as we find our way through this series of posts). The scenario is, as you may have already guessed, a service that can track Tasks. A Task currently looks like this:

public class Task
{
    public int Id { get; set; }
    public string Title { get; set; }
    public int Priority { get; set; }
}

In order to build a repository from this we first need to create a DbContext that is aware of the Task entity. The DbContext is the main class that handles all of the magic code-only stuff. If you want to know more what it does, head over to the Entity Framework Design blog.

I will also create an EntityConfiguration class. For now it will mostly just do what the default would have done anyway, but we will come back to it later on. I’m also going to derive from RepositoryBase to create a TaskRepository – also not necessary at this point, but it may come in handy if we want to handle some specialized queries. It also seems nicer to take a dependency on an ITaskRepository than on an IRepository<Task>, or at least that’s the way I feel..

public class BasicTasksContext : DbContext
{
    // This is not really necessary, but it may be nice as a reminder of which 
    // entities this context is supposed to handle
    public DbSet<Task> Tasks { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Configurations.Add(new TaskConfig());
    }
}

class TaskConfig : EntityConfiguration<Task>
{
    public TaskConfig()
    {
        HasKey(t => t.Id);
        MapSingleType(t => new
                               {
                                   TaskId = t.Id,
                                   Title = t.Title,
                                   Priority = t.Priority,
                               });
    }
}

public class TaskRepository : RepositoryBase<Task>, ITaskRepository
{
    public TaskRepository(DbContext dbContext)
        : base(dbContext)
    {
    }
}

Finally, the service that uses the TaskRepository. As you can see, I’m using manual constructor injection for now, but this will all be nicely done with Dependency Injection in a future post.. I promise. Maybe.

public class TaskService : Contract.ITaskService
{
    public IEnumerable<Contract.Task> ListTasks()
    {
        using (var context = new BasicTasksContext())
        {
            var taskRepository = new TaskRepository(context);

            var tasks = from t in taskRepository.List()
                    select new Contract.Task() { Id = t.Id, Title = t.Title };

            return tasks;
        }
    }

    public void AddTask(string title, int priority)
    {
        using (var context = new BasicTasksContext())
        {
            var taskRepository = new TaskRepository(context);

            taskRepository.Add(new Task{Title = title, Priority = priority});

            context.SaveChanges();
        }
    }

    public void RemoveTask(int id)
    {
        using (var context = new BasicTasksContext())
        {
            var taskRepository = new TaskRepository(context);

            var task = taskRepository.Get(t => t.Id == id);
            taskRepository.Delete(task);

            context.SaveChanges();
        }
    }
}

And that’s all there is to it! The first time you run it, the database will be created for you, containing a Tasks table with TaskId as the Primary Key. So sweet.

Summary

In this first episode, I’ve shown one way of implementing the Repository pattern using the recently released Entity Framework CTP 4. I must say that I have really fallen in love with this “Magic Unicorn Edition”. Being able to access a database, and even create it from scratch, without having to touch a line of SQL or even opening up Management Studio is very compelling to me!

So, what’s left? Well, quite a lot… Here are some things I’m considering writing about as the project moves along:

  • Adding filter strategies to the Repository (for sorting, paging etc).
  • Building a more complex data model
  • Solution structure
  • Adding Dependency Injection
  • A custom Fluent Interface for configuration
  • More code contracts
  • Versioning service endpoints

Comments, suggestions, criticism? Please leave a comment!

2 thoughts on “Episode 1 – Repository with EF Magic Unicorn (CTP 4)

  1. Pingback: Tweets that mention Episode 1 – Repository with EF Magic Unicorn (CTP 4) « Coding Insomnia -- Topsy.com

  2. Pingback: Episode 2 – Injecting the context « Coding Insomnia

Leave a Reply