Onion Architecture, Unit of Work and a generic Repository pattern - c#

This is the first time I am implementing a more domain-driven design approach. I have decided to try the Onion Architecture as it focuses on the domain rather than on infrastructure/platforms/etc.
In order to abstract away from Entity Framework, I have created a generic repository with a Unit of Work implementation.
The IRepository<T> and IUnitOfWork interfaces:
public interface IRepository<T>
{
void Add(T item);
void Remove(T item);
IQueryable<T> Query();
}
public interface IUnitOfWork : IDisposable
{
void SaveChanges();
}
Entity Framework implementations of IRepository<T> and IUnitOfWork:
public class EntityFrameworkRepository<T> : IRepository<T> where T : class
{
private readonly DbSet<T> dbSet;
public EntityFrameworkRepository(IUnitOfWork unitOfWork)
{
var entityFrameworkUnitOfWork = unitOfWork as EntityFrameworkUnitOfWork;
if (entityFrameworkUnitOfWork == null)
{
throw new ArgumentOutOfRangeException("Must be of type EntityFrameworkUnitOfWork");
}
dbSet = entityFrameworkUnitOfWork.GetDbSet<T>();
}
public void Add(T item)
{
dbSet.Add(item);
}
public void Remove(T item)
{
dbSet.Remove(item);
}
public IQueryable<T> Query()
{
return dbSet;
}
}
public class EntityFrameworkUnitOfWork : IUnitOfWork
{
private readonly DbContext context;
public EntityFrameworkUnitOfWork()
{
this.context = new CustomerContext();;
}
internal DbSet<T> GetDbSet<T>()
where T : class
{
return context.Set<T>();
}
public void SaveChanges()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
The Customer repository:
public interface ICustomerRepository : IRepository<Customer>
{
}
public class CustomerRepository : EntityFrameworkRepository<Customer>, ICustomerRepository
{
public CustomerRepository(IUnitOfWork unitOfWork): base(unitOfWork)
{
}
}
ASP.NET MVC controller using the repository:
public class CustomerController : Controller
{
UnityContainer container = new UnityContainer();
public ActionResult List()
{
var unitOfWork = container.Resolve<IUnitOfWork>();
var customerRepository = container.Resolve<ICustomerRepository>();
return View(customerRepository.Query());
}
[HttpPost]
public ActionResult Create(Customer customer)
{
var unitOfWork = container.Resolve<IUnitOfWork>();
var customerRepository = container.Resolve<ICustomerRepository>();;
customerRepository.Add(customer);
unitOfWork.SaveChanges();
return RedirectToAction("List");
}
}
Dependency injection with unity:
container.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>();
container.RegisterType<ICustomerRepository, CustomerRepository>();
Solution:
PROBLEMS?
Repository implementation (EF code) is very generic. It all sits in side the EntityFrameworkRepository<T> class. Concrete model repositories do not contain any of this logic. This saves me from writing tons of redundant code, but possibly sacrifices flexibility?
The ICustomerRepository and CustomerRepository classes are basically empty. They are purely there to provide abstraction. As far as I understand, this fits with the vision of the Onion Architecture, where infrastructure and platform-dependent code sits on the outside of your system, but having empty classes and empty interfaces feels wrong?
To use a different persistence implementation (say Azure Table Storage), then a new CustomerRepository class would need to be created and would inherit a AzureTableStorageRepository<T>. But this could lead to redundant code (multiple CustomerRepositories)? How would this effect mocking?
Another implementation (say Azure Table Storage) has limitations on transnational support so the a AzureTableStorageUnitOfWork class wouldn't work in this context.
Are there any other issues with the way I have done this?
(I have taken most of my inspiration from this post)

I can say that this code is good enough for the first time try but it does have some places to improve.
Let's go through some of them.
1. Dependency injection (DI) and usage of IoC.
You use the simplest version of Service Locator pattern - container instance itself.
I suggest you use 'constructor injection'. You can find more information here (ASP.NET MVC 4 Dependency Injection).
public class CustomerController : Controller
{
private readonly IUnitOfWork unitOfWork;
private readonly ICustomerRepository customerRepository;
public CustomerController(
IUnitOfWork unitOfWork,
ICustomerRepository customerRepository)
{
this.unitOfWork = unitOfWork;
this.customerRepository = customerRepository;
}
public ActionResult List()
{
return View(customerRepository.Query());
}
[HttpPost]
public ActionResult Create(Customer customer)
{
customerRepository.Add(customer);
unitOfWork.SaveChanges();
return RedirectToAction("List");
}
}
2. Unit of Work (UoW) scope.
I can't find lifestyle of IUnitOfWork and ICustomerRepository. I am not familiar with Unity but msdn says that TransientLifetimeManager is used by default. It means that you'll get a new instance every time when you resolve type.
So, the following test fails:
[Test]
public void MyTest()
{
var target = new UnityContainer();
target.RegisterType<IUnitOfWork, EntityFrameworkUnitOfWork>();
target.RegisterType<ICustomerRepository, CustomerRepository>();
//act
var unitOfWork1 = target.Resolve<IUnitOfWork>();
var unitOfWork2 = target.Resolve<IUnitOfWork>();
// assert
// This Assert fails!
unitOfWork1.Should().Be(unitOfWork2);
}
And I expect that instance of UnitOfWork in your controller differs from the instance of UnitOfWork in your repository. Sometimes it may be resulted in bugs. But it is not highlighted in the ASP.NET MVC 4 Dependency Injection as an issue for Unity.
In Castle Windsor PerWebRequest lifestyle is used to share the same instance of type within single http request.
It is common approach when UnitOfWork is a PerWebRequest component. Custom ActionFilter can be used in order to invoke Commit() during invocation of OnActionExecuted() method.
I would also rename the SaveChanges() method and call it simply Commit as it is called in the example and in the PoEAA.
public interface IUnitOfWork : IDisposable
{
void Commit();
}
3.1. Dependencies on repositories.
If your repositories are going to be 'empty' it is not needed to create specific interfaces for them. It is possible to resolve IRepository<Customer> and have the following code in your controller
public CustomerController(
IUnitOfWork unitOfWork,
IRepository<Customer> customerRepository)
{
this.unitOfWork = unitOfWork;
this.customerRepository = customerRepository;
}
There is a test that tests it.
[Test]
public void MyTest()
{
var target = new UnityContainer();
target.RegisterType<IRepository<Customer>, CustomerRepository>();
//act
var repository = target.Resolve<IRepository<Customer>>();
// assert
repository.Should().NotBeNull();
repository.Should().BeOfType<CustomerRepository>();
}
But if you would like to have repositories that are 'layer of abstraction over the mapping layer where query construction code is concentrated.' (PoEAA, Repository)
A Repository mediates between the domain and data mapping layers,
acting like an in-memory domain object collection. Client objects
construct query specifications declaratively and submit them to
Repository for satisfaction.
3.2. Inheritance on EntityFrameworkRepository.
In this case I would create a simple IRepository
public interface IRepository
{
void Add(object item);
void Remove(object item);
IQueryable<T> Query<T>() where T : class;
}
and its implementation that knows how to work with EntityFramework infrastructure and can be easily replaced by another one (e.g. AzureTableStorageRepository).
public class EntityFrameworkRepository : IRepository
{
public readonly EntityFrameworkUnitOfWork unitOfWork;
public EntityFrameworkRepository(IUnitOfWork unitOfWork)
{
var entityFrameworkUnitOfWork = unitOfWork as EntityFrameworkUnitOfWork;
if (entityFrameworkUnitOfWork == null)
{
throw new ArgumentOutOfRangeException("Must be of type EntityFrameworkUnitOfWork");
}
this.unitOfWork = entityFrameworkUnitOfWork;
}
public void Add(object item)
{
unitOfWork.GetDbSet(item.GetType()).Add(item);
}
public void Remove(object item)
{
unitOfWork.GetDbSet(item.GetType()).Remove(item);
}
public IQueryable<T> Query<T>() where T : class
{
return unitOfWork.GetDbSet<T>();
}
}
public interface IUnitOfWork : IDisposable
{
void Commit();
}
public class EntityFrameworkUnitOfWork : IUnitOfWork
{
private readonly DbContext context;
public EntityFrameworkUnitOfWork()
{
this.context = new CustomerContext();
}
internal DbSet<T> GetDbSet<T>()
where T : class
{
return context.Set<T>();
}
internal DbSet GetDbSet(Type type)
{
return context.Set(type);
}
public void Commit()
{
context.SaveChanges();
}
public void Dispose()
{
context.Dispose();
}
}
And now CustomerRepository can be a proxy and refer to it.
public interface IRepository<T> where T : class
{
void Add(T item);
void Remove(T item);
}
public abstract class RepositoryBase<T> : IRepository<T> where T : class
{
protected readonly IRepository Repository;
protected RepositoryBase(IRepository repository)
{
Repository = repository;
}
public void Add(T item)
{
Repository.Add(item);
}
public void Remove(T item)
{
Repository.Remove(item);
}
}
public interface ICustomerRepository : IRepository<Customer>
{
IList<Customer> All();
IList<Customer> FindByCriteria(Func<Customer, bool> criteria);
}
public class CustomerRepository : RepositoryBase<Customer>, ICustomerRepository
{
public CustomerRepository(IRepository repository)
: base(repository)
{ }
public IList<Customer> All()
{
return Repository.Query<Customer>().ToList();
}
public IList<Customer> FindByCriteria(Func<Customer, bool> criteria)
{
return Repository.Query<Customer>().Where(criteria).ToList();
}
}

The only con I see is that you are highly dependent on your IOC tool, so make sure your implementation is solid. However, this is not unique to Onion designs. I have used Onion on a number of projects and have not run into any real 'gotchas".

I see couple of serious problems in code.
The 1st problem is relashionship between repositories and UoW.
var unitOfWork = container.Resolve<IUnitOfWork>();
var customerRepository = container.Resolve<ICustomerRepository>();
Here is implicit dependency. Repository will not work itself without UoW! Not all repositories needs to be connected with UoW. For example what about stored procedures? You have stored procedure and you hide it behind repository. Stored procedure invokation uses separate transaction! At least not in all cases. So if I resolve the only repository and add item then it will not work. Moreover this code will not work if I set Transient life license because repository will have another UoW instance. So we have tight implicit coupling.
The 2nd problem you create tight coupling between DI container engine and use it as service locator! Service locator is not good approach to implement IoC and aggregation. In some case it is anti pattern. DI container should be used

Related

UnitOfWork & Generic Repository, SOLID principles with Custom Repository

I'm using UnitOfWork and Repository patterns in my project. I'm trying to code clean.
This is my IUnitOfWork.cs (Application Layer)
public interface IUnitOfWork : IDisposable
{
int Save();
IGenericRepository<TEntity> Repository<TEntity>() where TEntity : class;
}
The implementation UnitOfWork.cs : (Persistence Layer)
public class UnitOfWork : IUnitOfWork
{
private readonly DBContext _context;
private Hashtable _repositories;
public UnitOfWork(DBContext context)
{
_context = context;
}
public IGenericRepository<T> Repository<T>() where T : class
{
if (_repositories == null)
_repositories = new Hashtable();
var type = typeof(T).Name;
if (!_repositories.ContainsKey(type))
{
var repositoryType = typeof(GenericRepository<>);
var repositoryInstance =
Activator.CreateInstance(repositoryType
.MakeGenericType(typeof(T)), _context);
_repositories.Add(type, repositoryInstance);
}
return (IGenericRepository<T>)_repositories[type];
}
public int Save()
{
// Save changes with the default options
return _context.SaveChanges();
}
// etc.. Dispose()
}
My IGenericRepository.cs : (Application Layer)
public interface IGenericRepository<TEntity>
where TEntity : class
{
void Update(TEntity entity);
void Delete(object id);
void InsertList(IEnumerable<TEntity> entities);
// etc..
}
In my service : (Application Layer)
var result = UnitOfWork.Repository<Entities.Example>().Delete(id);
And using Unity, I inject the dependency in the container.
container.RegisterType<IUnitOfWork, UnitOfWork>(new HierarchicalLifetimeManager())
And it works like a charm.
Now I have a custom Repository ICustomRepository:
public interface ICustomRepository: IGenericRepository<Entities.Custom>
{
void Test();
}
How can I access the Test() function using my IUnitOfWork?
var result = UnitOfWork.Repository<Entities.Custom>().Test(); // not working
UPDATE:
#Thomas Cook give me a way using cast :
(UnitOfWork.Repository<Entities.Custom>() as ICustomRepository).Test();
I get a NullReferenceException:
System.NullReferenceException: 'Object reference not set to an instance of an object.'
You'll have to cast, because UnitOfWork Repository method returns a IGenericRepository which doesn't declare Test. So you'll need to cast the returned value to a ICustomRepository which inherits IGenericRepository and bolts on the Test method.
Whilst casting would work (if the repository wouldn't be null) you could ask yourself is this is useful; What good is an abstraction of you're going to depend on knowing its details, i.e.: the caller now knows it actually is a non-generic interface and type, namely a ICustomRepository (btw the reason you get the null ref probably is because UnitOfWork only creates the generic repositories and your custom repo doesn't exist).
A better (IMO) and more explicit way to design your Unit of Work not in a generic way but list all repositories:
public interface IUnitOfWork : IDisposable
{
int Save();
ICustomRepository CustomRepository {get;}
IGenericRepository<Entities.Example> ExampleRepository {get;}
// etc...
}
This way you don't need any casting or know its details.
Furthermore, I would recommend to pass all repositories to the constructor of the UnitOfWork from your dependency injection and don't make its responsibility too big.
public UnitOfWork(DBContext context, ICustomRepository customRepository ...)
{
//
}
Just make sure you use the same instance of DbContext in your Unit of Work as the one that's injected into your repositories.

Inject a repository which has Generic as well as Concrete Implementation to a controller

I am making a generic repository but for some entities I also need functionalities not provided by the generic repository. I have an interface IGenericRepository and concrete implementation as GenericRepository with basic CRUD operations. Further I have a studentRepository that uses the generic repository but also has functionalities of its own independent from the Generic Repository for which i have an Interface called IStudentRepository.
Here is the sample code:
public interface IGenericEntityRepository<T>
{
Delete(T entity);
T Get(int id);
IEnumerable<T> GetAll();
Add(T entity);
Update(T entity);
}
public class GenericEntityRepository<T> : IGenericEntityRepository<T> where T : class
{
protected readonly ApplicationDbContext _applicationDbContext;
public GenericEntityRepository(ApplicationDbContext applicationDbContext)
{
this._applicationDbContext = applicationDbContext;
}
//Generic Repository Implementations....
}
public interface IStudentRepository
{
string GetFullName(Student student)
double GetGpa(Student student)
}
public class StudentRepository: GenericRepository<Student>, IStudentRepository
{
public StudentRepository(ApplicationDbContext applicationDbContext) : base(applicationDbContext)
{}
//IStudentRepository functions' implementations...
}
Now I need to inject this StudentRepository to my StudentsController
public class StudentsController : Controller
{
private readonly IGenericEntityRepository<Student> _genericStudentRepository;
public StudentsController(IGenericEntityRepository<Student> _genericStudentRepository)
{
this._genericStudentRepository = genericRepository;
}
public void testAccessibility()
{
this._genericStudentRepository.GetAll() //valid call
this._genericStudentRepository.GetAllGpa() //invalid Call
***As expected cause IGenericEntityRepository doesn't have that ***function
}
}
As you can see the probelem here, if I inject IGenericEntityRepository I only get the genericrepository functionalities. If i want the functionalities of Student repository not included in genericRepository I have to inject both IGenericEntityRepository and IStudentRepository like below and vice versa.
public class StudentsController : Controller
{
private readonly IGenericEntityRepository<Student> _genericStudentRepository;
private readonly IStudentRepository _studentsRepository;
public StudentsController(IGenericEntityRepository<Student> _genericStudentRepository, IStudentRepository studentsRepository)
{
this._genericStudentRepository = genericRepository;
this.__studentsRepository = studentsRepository;
}
public void testAccessibility()
{
this._genericStudentRepository.GetAll() //valid call
this._studentsRepository.GetAllGpa() //valid call
}
}
Is there a better way to do this? Doesn't feel right injecting two contextually same but coding wise different objects like this.
You can have IStudentRepository extend IGenericEntityRepository<T>:
public interface IStudentRepository : IGenericEntityRepository<Student>
{
string GetFullName(Student student)
double GetGpa(Student student)
}
Now injecting IStudentRepository should be enough to use all the functions.

How to access a method in the context through unit of work?

If I have the following Context :
public partial class HRMainDataCTX : DbContext
{
public HRMainDataCTX()
: base("name=HRMainDataCTX")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
throw new UnintentionalCodeFirstException();
}
//DbSets
public virtual int SEARCHEMPLOYEE(Nullable<decimal> p_EMP_NUM, string p_EMP_NAME)
{
var p_EMP_NUMParameter = p_EMP_NUM.HasValue ?
new ObjectParameter("P_EMP_NUM", p_EMP_NUM) :
new ObjectParameter("P_EMP_NUM", typeof(decimal));
var p_EMP_NAMEParameter = p_EMP_NAME != null ?
new ObjectParameter("P_EMP_NAME", p_EMP_NAME) :
new ObjectParameter("P_EMP_NAME", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.ExecuteFunction("SEARCHEMPLOYEE", p_EMP_NUMParameter, p_EMP_NAMEParameter);
}
}
Now i implement Unit of work like this :
public class HRCTX : IDisposable
{
private readonly HRMainDataCTX _context;
public HRCTX()
{
_context = new HRMainDataCTX();
}
public HRCTX(HRMainDataCTX context)
{
_context = context;
}
public int Save()
{
return _context.SaveChanges();
}
public HRMainDataCTX Context
{
get { return _context; }
}
public void Dispose()
{
_context.Dispose();
}
}
I don't know how to access the method (stored procedure) SEARCHEMPLOYEE through UOW in my code behind.
Well, in your case you would simply add another "Proxy-Method" for this method to your HRCTX proxy / UOW class, or - since HRCTX provides access to its underlying context - call it directly on the context like this:
HRCTX uow = new HRCTX(someContext);
uow.Context.SEARCHEMPLOYEE(123, "123");
But I also wanted to emphasize that the DbContext already represents a Unit of Work pattern (combined with a Repository pattern, see here). You are basically creating a proxy for your context, which - as far as I can see in this example - adds no further benefits or functionality, so I'd suggest to at least think about directly using your HRMainDataCTX and possibly getting rid of the HRCTX class.
You may need to implement repositories along with your Unit Of work pattern if you want to encapsulate your DbContext and your business logic. (As suggested in the AspNet guidelines)
In a generic manner, your unit of work can handle repositories like this:
public class HRCTX : IDisposable
{
private readonly HRMainDataCTX _context;
private Dictionary<Type, object> Repositories { get; set; }
public HRCTX()
{
_context = new HRMainDataCTX();
this.Repositories = new Dictionary<Type, object>();
}
//Get and add a repository to the dictionary if ot does not exist
public IRepository<TEntity> GetNonGenericRepository<TEntity, TRepository>() where TEntity : class
{
if (this.Repositories.Keys.Contains(typeof(TRepository)))
{
return this.Repositories[typeof(TRepository)] as IRepository<TEntity>;
}
var repoType = typeof(TRepository);
var constructorInfo = repoType.GetConstructor(new Type[] { typeof(DbContext)});
IRepository<TEntity> repository = (IRepository<TEntity>) constructorInfo.Invoke(new object[] { this._context});
this.Repositories.Add(typeof(TRepository), repository);
return repository;
}
public IRepository<TEntity> GetGenericRepository<TEntity>() where TEntity : class
{
if (this.Repositories.Keys.Contains(typeof(TEntity)))
{
return this.Repositories[typeof(TEntity)] as IRepository<TEntity>;
}
IRepository<TEntity> repository = new Repository<TEntity>(this._context);
this.Repositories.Add(typeof(TEntity), repository);
return repository;
}
}
The interface and base class of your repositories:
public interface IRepository<TEntity> where TEntity : class
{
TEntity Find(Expression<Func<TEntity, bool>> match);
}
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
protected DbContext Context { get; set; }
public Repository(DbContext context)
{
this.Context = context;
}
public TEntity Find(Expression<Func<TEntity, bool>> match)
{
return Context.Set<TEntity>().SingleOrDefault(match);
}
}
Now is the part where you clearly encapsulate your business logic:
public class EmployeeRepository : Repository<Employee>
{
public EmployeeRepository(DbContext context) : base(context) {
}
public override Employee Find(Expression<Func<TEntity, bool>> match)
{
// You can either use the base class method or implement your custom logic
}
//This is where you encapsulate your business logic
public Employee FindSpecific(Nullable<decimal> employeeNum, string employeeName){
return this.Context.SEARCHEMPLOYEE(employeeNum, employeeName);
}
}
Then you can use your Unit Of Work to access you business logic in a domain driven design way.
HRCTX unitOfWork= new HRCTX(dbContext);
unitOfWork.GetNonGenericRepository<Employee, EmployeeRepository>().FindSpecific(1337,"1337");
It can seem to be too much for what you expected as an answer but I think you need to structure your application that way if you don't want to expose you DbContext / Dal directly.
Hope it helps !
This webpage documents exactly how to accomplish your goal.
http://www.asp.net/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application

Ninject Named binding with IGenericRepository

I'm developing an ASP.NET MVC 4 Web Api, with C#, .NET Framework 4.0, Entity Framework Code First 6.0 and Ninject.
I have two different DbContext custom implementations to connect with two different databases.
This is my NinjectConfigurator class (partial):
private void AddBindings(IKernel container)
{
container.Bind<IUnitOfWork>().
To<TRZICDbContext>().InRequestScope().Named("TRZIC");
container.Bind<IUnitOfWork>().
To<INICDbContext>().InRequestScope().Named("INIC");
container.Bind<IGenericRepository<CONFIGURATIONS>>().
To<GenericRepository<CONFIGURATIONS>>();
container.Bind<IGenericRepository<INCREMENTAL_TABLE>>().
To<GenericRepository<INCREMENTAL_TABLE>>();
// More implementation...
}
CONFIGURATIONS is a TRZIC table and INCREMENTAL_TABLE is an INIC table.
I'm using a IGenericRepository and here it's where I have the problems:
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
protected DbSet<TEntity> DbSet;
private readonly DbContext dbContext;
public GenericRepository(IUnitOfWork unitOfWork)
{
dbContext = (DbContext)unitOfWork;
DbSet = dbContext.Set<TEntity>();
}
// Hidden implementation..
}
I don't know how to use the [Named("TRZIC")] here public GenericRepository(IUnitOfWork unitOfWork) or maybe I need to use it elsewhere.
Here the IUnitOfWork implementation depends on TEntity.
Any advice?
Let's start with the basics.
As far as i know named bindings work only with constant values attributed in code, like the [Named("foo")] attribute, or otherwise by using "service location" like IResolutionRoot.Get<T>(string name). Either does not work for your scenario, so a named binding is out of the question.
That leaves you with conditional bindings (.When(...) methods).
You've got 2 database with n entities each.
2 Database means two configurations means 2 different IUnitOfWork configuration.
However, the "user" is not requesting a specific database, but a specific entity.
Thus you'll need a map entity-->database (a dictionary). I don't think there's a way to get around that, but you may devise some kind of convention & implement it by convention, so you don't have to type and maintain a lot of code.
Solution 1: .WhenInjectedInto<>
with out of the box ninject features, and lots of manual labor:
Bind<IUnitOfWork>().To<UnitOfWorkOfDatabaseA>()
.WhenInjectedInto<IRepository<SomeEntityOfDatabaseA>>();
Bind<IUnitOfWork>().To<UnitOfWorkOfDatabaseA>()
.WhenInjectedInto<IRepository<SomeOtherEntityOfDatabaseA>>();
Bind<IUnitOfWork>().To<UnitOfWorkOfDatabaseB>()
.WhenInjectedInto<IRepository<SomeEntityOfDatabaseB>>();
you get the drift,.. right?
Solution 2.1: Custom When(..) implementation
Not so much manual labor and maintenance anymore.
Let me just dump the code on you, see below:
public interface IRepository
{
IUnitOfWork UnitOfWork { get; }
}
public class Repository<TEntity> : IRepository<TEntity>
{
public IUnitOfWork UnitOfWork { get; set; }
public Repository(IUnitOfWork unitOfWork)
{
UnitOfWork = unitOfWork;
}
}
public interface IUnitOfWork { }
class UnitOfWorkA : IUnitOfWork { }
class UnitOfWorkB : IUnitOfWork { }
public class Test
{
[Fact]
public void asdf()
{
var kernel = new StandardKernel();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>));
kernel.Bind<IUnitOfWork>().To<UnitOfWorkA>()
.When(request => IsRepositoryFor(request, new[] { typeof(string), typeof(bool) })); // these are strange entity types, i know ;-)
kernel.Bind<IUnitOfWork>().To<UnitOfWorkB>()
.When(request => IsRepositoryFor(request, new[] { typeof(int), typeof(double) }));
// assert
kernel.Get<IRepository<string>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkA>();
kernel.Get<IRepository<double>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkB>();
}
private bool IsRepositoryFor(IRequest request, IEnumerable<Type> entities)
{
if (request.ParentRequest != null)
{
Type injectInto = request.ParentRequest.Service;
if (injectInto.IsGenericType && injectInto.GetGenericTypeDefinition() == typeof (IRepository<>))
{
Type entityType = injectInto.GetGenericArguments().Single();
return entities.Contains(entityType);
}
}
return false;
}
}
Solution 2.2 Custom convention based When(...)
Let's introduce a small convention. Entity names of database TRZIC start with TRZIC, for example TRZIC_Foo. Entity names of database INIC start with INIC, like INIC_Bar. We can now adapt the previous solution to:
public class Test
{
[Fact]
public void asdf()
{
var kernel = new StandardKernel();
kernel.Bind(typeof (IRepository<>)).To(typeof (Repository<>));
kernel.Bind<IUnitOfWork>().To<UnitOfWorkA>()
.When(request => IsRepositoryFor(request, "TRZIC")); // these are strange entity types, i know ;-)
kernel.Bind<IUnitOfWork>().To<UnitOfWorkB>()
.When(request => IsRepositoryFor(request, "INIC"));
// assert
kernel.Get<IRepository<TRZIC_Foo>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkA>();
kernel.Get<IRepository<INIC_Bar>>()
.UnitOfWork.Should().BeOfType<UnitOfWorkB>();
}
private bool IsRepositoryFor(IRequest request, string entityNameStartsWith)
{
if (request.ParentRequest != null)
{
Type injectInto = request.ParentRequest.Service;
if (injectInto.IsGenericType && injectInto.GetGenericTypeDefinition() == typeof (IRepository<>))
{
Type entityType = injectInto.GetGenericArguments().Single();
return entityType.Name.StartsWith(entityNameStartsWith, StringComparison.OrdinalIgnoreCase);
}
}
return false;
}
}
This way we don't need explicit mapping (EntityA, EntityB, EntityC) => DatabaseA, (EntityD, EntityE, EntityF) => DatabaseB).
If you say that IUnitOfWork depends on TEntity why not make IUnitOfWork generic too?
public class TRZIC {}
public class INIC {}
public interface IUnitOfWork<TEntity> {}
public class TRZICDbContext : DbContext, IUnitOfWork<TRZIC> {}
public class INICDbContext : DbContext, IUnitOfWork<INIC> {}
public interface IGenericRepository<TEntity> {}
public class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
public GenericRepository(IUnitOfWork<TEntity> unitOfWork)
{
var dbContext = (DbContext) unitOfWork;
}
}
private static void AddBindings(IKernel container)
{
container
.Bind<IUnitOfWork<TRZIC>>()
.To<TRZICDbContext>();
container
.Bind<IUnitOfWork<INIC>>()
.To<INICDbContext>();
container
.Bind<IGenericRepository<TRZIC>>()
.To<GenericRepository<TRZIC>>();
container
.Bind<IGenericRepository<INIC>>()
.To<GenericRepository<INIC>>();
}
Another solution that also leverages code readability:
public interface IUnitOfWork {}
// both named A and B
public class UnitOfWorkA : IUnitOfWork {}
public class UnitOfWorkB : IUnitOfWork {}
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class
{
protected DbSet<TEntity> DbSet;
private readonly DbContext dbContext;
public GenericRepository(IUnitOfWork unitOfWork)
{
dbContext = (DbContext)unitOfWork;
DbSet = dbContext.Set<TEntity>();
}
// other IGenericRepository methods
}
public class GenericRepositoryForA<TEntity> : GenericRepository<TEntity>
{
public GenericRepositoryForA([Named("A")]IUnitOfWork unitOfWork)
: base(unitOfWork)
{
}
}
public class GenericRepositoryForB<TEntity> : GenericRepository<TEntity>
{
public GenericRepositoryForB([Named("B")]IUnitOfWork unitOfWork)
: base(unitOfWork)
{
}
}
This allows you to ask for a specific database context as a dependency, or get both of them if required. And you only need to implement GenericRepository once.
It greatly improvises code visiblity because you actually know which database context you are using by looking at the variable type/name, instead of getting a IUnitOfWork injected without any visual detail on its actual type.
I'd suggest adding some extra interfaces if you want to unittest it (you should!).
Simply adding
public interface IGenericRepositoryForA<TEntity> : IGenericRepository<TEntity>
and just let GenericRepositoryForA<TEntity> implement it aswell.
Another solution:
private void AddBindings(IKernel container)
{
container.Bind<IUnitOfWork>().To<TRZICDbContext>().InRequestScope();
container.Bind<IGenericRepository<CONFIGURATIONS>>().
To<GenericRepository<CONFIGURATIONS>>();
container.Bind<IGenericRepository<INCREMENTAL_TABLE>>().
To<GenericRepository<INCREMENTAL_TABLE>>().WithConstructorArgument("unitOfWork", new INICDbContext());
// More code..
}
I have used WithConstructorArgument to indicate that I want to use INICDbContext.
I don't know if this is correct or not.

Using multiple repositories based on a base concrete class

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.
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
}

Categories

Resources