Written on 4/18/2014 in Web development

First phase - Repositories


The vorpal story Data First phase

repo.GetHelloWorld()

The repository pattern and unit of work pattern are ... already present in entity framework, see the previous post for how I handled the data layer. That's what I read somewhere on the massive battleground of 'Internet'. While that's true, I thought about why we wrote repositories in the first place. It abstracts a layer, so that the underlying layer can easily be altered. Now, when you're thinking about the database layer, entity framework's access model is a very good abstraction making it easy to switch underlying storage systems.

But I was genuinely not certain I would keep using entity framework. So in my personal case, I decided I wanted to abstract the entity framework layer as well. I conclude the discussions I read are all a collection of nonsense and/or personal opinions. Several of my general points of view come to mind here, watch out because these might blow your mind:

There will always be someone better than you, just make sure he's not better at everything

and

Bachelors' wives and maidens' children are well taught. (I translated this from a Dutch proverb, so sorry if I'm verbally abusing a minority here or this proverb does not make any sense.. :p)

Repositories

Which brings me back to the actual post's meaning. I already had the base code for a repository pattern lying around somewhere so I'll just use that. While I'm sure I wrote this based on an article somewhere, I can't find the source anywhere. I use some form of a publish and subscribe pattern where the repositories subscribe to the unit of work. I find this method easy and it allows for different contexts. It's not perfect but it does the job. A big negative point is, that if 3 repositories are added with the same context, it will save the same context 3 times. I'm sure there's a way around this, but is it really worth the trouble? A beautifully designed representation of this solution:

Repository and uow

PubSub uow

The base repository:

public class RepositoryBase<TC, T> : IRepositoryBase<T>
    where TC : DbContext
    where T : class
{
    private readonly TC _context;

    public RepositoryBase(TC context)
    {
        _context = context;
    }

    public virtual T Add(T entity)
    {
        entity = _context.Set<T>().Add(entity);
        _context.Entry(entity).State = EntityState.Added;
        return entity;
    }

    public virtual T Update(T entity)
    {
        if (_context.Entry(entity).State == EntityState.Detached)
        {
            entity = _context.Set<T>().Attach(entity);
        }
        _context.Entry(entity).State = EntityState.Modified;
        return entity;
    }

    public virtual T GetById(object id)
    {
        return _context.Set<T>().Find(id);
    }

    public virtual T Get(Func<T, bool> expression)
    {
        return _context.Set<T>().Where(expression).FirstOrDefault();
    }

    public virtual IEnumerable<T> GetAll()
    {
        return _context.Set<T>();
    }

    public virtual IEnumerable<T> GetMany(Func<T, bool> expression)
    {
        return _context.Set<T>().Where(expression);
    }

    public virtual void Remove(int id)
    {
        T entity = GetById(id);

        _context.Set<T>().Remove(entity);
        _context.Entry(entity).State = EntityState.Deleted;
    }

    public virtual void SaveChanges()
    {
        _context.SaveChanges();
    }
}

The unit of work class:

public class UnitOfWork : IUnitOfWork
{
    private List<IRepository> _repositories;

    public void Register(IRepository repository)
    {
        if (_repositories == null)
        {
            _repositories = new List<IRepository>();
        }
        _repositories.Add(repository);
    }

    public void SaveChanges()
    {
        _repositories.ForEach(m => m.SaveChanges());
    }
}

An implementation of the base repository:

public class TopicRepository : RepositoryBase<VorpalContext, Topic>, ITopicRepository
{
    /// <summary>
    /// Constructor
    /// </summary>
    /// <param name="uow">Injected by ninject - Unit Of Work</param>
    /// <param name="ctx">Injected by ninject - Context</param>
    public TopicRepository(IUnitOfWork uow, VorpalContext ctx)
        : base(ctx)
    {
        // Register this repository
        uow.Register(this);
    }
}

The repositories are loaded where needed using dependency injection. I also use dependency injection to inject the context. It's an easy way to define the scope in which the context is used. I'll talk about dependency injection in the next post.

Newer Older Top
blog comments powered by Disqus