Reputation: 4964
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.'
Upvotes: 5
Views: 892
Reputation: 6252
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.
Upvotes: 1
Reputation: 4853
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.
Upvotes: 1