Question

I've found that in my UnitOfWork I have a repository for each type of entity and am not using aggregate roots, so I'm trying to fix that. Tackling the idea of computer inventory, I currently have my UnitOfWork structured as such:

public class UnitOfWork : IUnitOfWork
{
    private readonly ReportingDbContext _dbContext = null;

    public UnitOfWork()
    {
        _dbContext = new ReportingDbContext();
    }

    public void Commit()
    {
        _dbContext.SaveChanges();
    }

    // Inventory
    public IRepository<ComputerEntity> Computers {get { return new Repository<ComputerEntity>(_dbContext); }}
    public IRepository<NetworkAdapterEntity> NetworkAdapters { get { return new Repository<NetworkAdapterEntity>(_dbContext); } }
    // plus a bunch more
}

I want only my aggregate root to appear there, which should be easy enough to do. I think the issue is that I'm using a single repository class and feeding in the type when I new it up. I believe the answer is to have multiple repositories, each one corresponding to an aggregate root. What is nice about this one generic repository that I'm using for each type is that it handles all my Entity Framework stuff like finding by ID, saving to the DbSet, etc. My generic repository is setup as such:

public class Repository<T> : IRepository<T> where T : class
{
    protected DbContext DbContext { get; set; }
    protected DbSet<T> DbSet { get; set; }

    public Repository(DbContext dbContext)
    {
        if (dbContext == null)
        {
            throw new ArgumentNullException("dbContext");
        }
        DbContext = dbContext;
        DbSet = DbContext.Set<T>();
    }

    public IQueryable<T> GetAll()
    {
        return DbSet;
    }

    public IQueryable<T> Find(System.Linq.Expressions.Expression<Func<T, bool>> predicate)
    {
        return DbSet.Where(predicate);
    }

    // the rest of the implementation omitted for brevity
}

This repository uses an interface that all my yet-to-be-created aggregate root repositories should use:

public interface IRepository<T> where T : class
{
    IQueryable<T> GetAll();
    IQueryable<T> Find(Expression<Func<T, bool>> predicate);
    T GetById(int id);
    void Remove(T entity);
    void Add(T newEntity);
}

Now here is the real meat of the question. I have the above interface implemented nicely in my concrete Repository class, and I want that same functionality in all the aggregate root repositories that I will be making. I don't want to ever directly use this generic repository, as I just want to use it for a base to get at the basic CRUD stuff it does with Entity Framework. I don't want to repeat the already implemented generic repository stuff, just inherit it. More importantly, I want to design this correctly the first time.

Would it be appropriate to create my aggregate root based repository as such:

public interface IComputerRepository
{
    string ComputerSpecificMethod(string param);  
}

public class ComputerRepository : Repository<ComputerEntity>, IComputerRepository
{
    public ComputerRepository(DbContext dbContext) : base(dbContext)
    {
        // 
    }

    public string ComputerSpecificMethod(string param)
    {
        // do stuff
        return "test";
    }
}

Then use this new fancy repository (and others like it) in my UnitOfWork as such:

public IRepository<ComputerEntity> Computers {get { return new ComputerRepository(_dbContext); }}

Instead of:

public IRepository<ComputerEntity> Computers {get { return new Repository<ComputerEntity>(_dbContext); }}

The goal is to stick to the UnitOfWork/Repository pattern, and I'm unsure if this is the proper way of doing this.

Was it helpful?

Solution

I found that the way to do this that works for me is to have the interface for each custom repository in my unit of work class as such:

    public IInventoryRepository Computers { get { return new InventoryRepository(_dbContext); } }

It is implemented in its own class of course. To get it to inherit properly, I did this:

public class InventoryRepository : GenericRepository<ComputerEntity>, IInventoryRepository
{


    public InventoryRepository(DbContext dbContext) : base(dbContext)
    {

    }

  // your custom methods go here
 }

I then can use this in my WCF service as such:

 using (var uoW = new UnitOfWork())
        {
            var repo = uoW.Computers;
            var computerEntity = repo.FindComputerByHostname(hostname, client);
            // do more stuff
        }
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top