Using Automapper with generics - c#

I have a base class Repository which contains base functionality for a set of classes that inherit from it such as UserRepository or DepartmentRepository.
I'm using automapper to map between my entity framework objects and my domain objects.
public class Repository<TEntity> : IRepository<TEntity> where TEntity : class {
protected readonly DbContext Context;
public Repository(DbContext context) {
Context = context;
}
public TEntity Get(int id) {
return Context.Set<TEntity>().Find(id);
}
}
public class UserRepository : Repository<User>, IUserRepository {
public UserRepository(DbContext context) : base(context) {
}
public User GetUserByNTId(string NTId) {
return Mapper.Map<User>(DbContext.Users.SingleOrDefault(u => u.NTId == NTId));
}
}
GetUserByNTId will work because I can use automapper in the return statement. But Get will not work because it deals with TEntity and I don't know how you can tell automapper to examine the type of TEntity and look for a matching mapping.
How can I change the return statement of the Get function so that it will work for all my derived repositories and still use automapper? Or do I just have to take all my general functions and push them down into the derived classes and eliminate the Repository base class?

It's a very bad idea to for mixing AutoMapper and other responsibilities when querying from a Repository pattern. It's also of course a violation of the Single Responsibility Principle.
A naive non tested implementation will be:
public class ExampleOfGenericRepository<TEntity> : Repository<TEntity>
where TEntity : class
{
public ExampleOfGenericRepository(DbContext context)
: base(context)
{
}
public TEntity GetById(int id)
{
return Mapper.Map<TEntity>(Get(id));
}
}

Related

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.

Bind generic type (scanning) to concrete instance with generic method call

Using StructureMap I want to bind IQueryable<T> to ApplicationDbContext.Set<T>().AsQueryable().
So I can inject like this.
public class Foo
{
public Foo(IQueryable<MyEntity> query)
{
}
}
I've gotten this far
config.For(typeof(IQueryable<>))
.Use(x =>
x.GetInstance<ApplicationDbContext>().Set<TNotWorking>().AsQueryable());
But I can't figure out how to get the TNotWorking working :) I guess reflection isn't an option here, also I would avoid it if possible.
As pointed out in the comments, it's not possible w/o reflection or implementing each entity as a type in your project.
The last approach could look like this. When you create a base class which implements IQueryable<T>, then the code required for adding new entities is minimal and will also work when there is more than a single DbContext available for injection, which is almost always the case in any non-trivial demo application.
public abstract class QueryableEntityBase<TEntity> : IQueryable<TEntity> where TEntity : class
{
protected QueryableEntityBase(DbContext context)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
Queryable = context.Set<TEntity>().AsQueryable();
}
public Type ElementType => Queryable.ElementType;
public Expression Expression => Queryable.Expression;
public IQueryProvider Provider => Queryable.Provider;
protected IQueryable<TEntity> Queryable { get; }
private DbContext Context { get; }
public IEnumerator<TEntity> GetEnumerator() => Queryable.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => Queryable.GetEnumerator();
}
// You need to create this per entity you want to be injectable
public class MyQueryableEntity : QueryableEntityBase<MyEntity>
{
public MyQueryableEntity(ApplicationDbContext context) : base(context) { }
}
This has the additional advantage that you can change the underlying query/persistence provider by entity, by changing QueryableEntityBase<T> base with MonogoDbQueryableEntityBase<T> which uses an IMongoClient instead of DbContext.
The registration should be something along the line of (not familiar with StructureMap, you'd need to register all of it's types though or scan the assembly).
config.For(typeof(IQueryable<>)).Use(typeof(QueryableEntityBase<>));
In a simple case where you only have a single database, you could also make the base class non-abstract and just resolve QueryableEntity<T>, but like I said you'll hit the limitation of one single DbContext per app sooner or later, so it's best to be done explicitly.
Or alternatively extend the implementation so you can define the context too
public class QueryableEntityBase<TContext, TEntity> : IContextSetQueryable<TDbContext, TEntity>, IQueryable<TEntity> where TEntity : class, TContext : DbContext
{
private TContext Context { get; }
protected QueryableEntityBase(TContext context)
{
Context = context ?? throw new ArgumentNullException(nameof(context));
Queryable = context.Set<TEntity>().AsQueryable();
}
}
But then you need an additional interface:
public interface IContextSetQueryable<TContext, TContext> : IQueryable<TEntity> where TContext : DbContext { }
Then inject IContextSetQueryable<TContext, TContext> entity into your services.
But then you lose the ability to have persistence agnostic domain, since you'll need the ability to reference DbContext and it's subtypes, so it's not really elegant and you could as well use database specific interfaces, such as
public interface ISomethingDatabase
{
IQueryable<User> Users { get; }
IQueryable<Customer> Customers { get; }
...
}

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.

Issue with IEnumerable<TEntity>

I want to write a common method which returns any model like product, sales,etc. Something like this (.net 3.5; I'm not using entity framework)
public class ProductRepository<TEntity> : IProduct<TEntity>
where TEntity : class
{
public IEnumerable<TEntity> GetProductList(string Type)
{
IEnumerable<Product> fLit = from p in ProductList
select p;
return fLit;
}
}
But I'm getting the following error
Cannot implicitly convert type System.Collections.Generic.IEnumerable<Product>' to
System.Collections.Generic.IEnumerable<TEntity>. An explicit conversion exists (are you missing a cast?)
Any help appreciated. Thanks in advance.
I'm afraid you have to change design of your Domain, well this is not how Repository Pattern going to implement. First of all You have to have a base class for your Domain Models something simple like below (Of course this is not necessary):
public class EntityBase {
public virtual int Id { get; set; }
}
then you must have a generic IRepository interface :
public interface IRepository<TEntity> where TEntity : EntityBase {
TEntity FindOne(int id);
}
after you implement generic IRepository interface you need to have a concrete Repository class which is inherited from you generic interface, like this :
public class Repository<TEntity> : IRepository<TEntity> where TEntity : EntityBase {
private readonly DbContext _dbContext;
private readonly DbSet<TEntity> _dbSet;
public Repository(DbContext dbContext) {
_dbContext = dbContext;
_dbSet = _dbContext.Set<TEntity>();
}
public IQueryable<TEntity> Entities {
get { return _dbSet; }
}
public TEntity FindOne(int id) {
return Entities.FirstOrDefault(t => t.Id == id);
}
}
this is neat, so as you can see here we expect DbContext parameter for Repository class constructor. Also we take the advantage of our entity base's Id property to find what exactly we want.
Well till now you implement a basics of Repository pattern, from now on, you need to create a Repository class for each Domain Entity. let's implement what you've asked here :
public class ProductRepository : Repository<Product> {
public ProductRepository(DbContext dbContext)
: base(dbContext) {
}
public IEnumerable<Product> GetProductList(string Type) {
IEnumerable<Product> fLit = from p in Entities select p;
return fLit;
}
}
Hope this help.
The error is pretty clear: a TEntity is not a Product. In .Net 4.0 you could use covariance to fix this, but in .Net 3.5 you may do the following:
Change your type constraint from where TEntity : class to where TEntity : Product. You are already assuming this in the method, so do this so the compiler can enforce it.
Use LINQ to explicitly cast the results to TEntities: return fLit.Cast<TEntity>();
In .NET 3.5 you cannot cast a generic type like that. So just keep your enumerable as a generic type. Change the line to:
IEnumberable<TEntity> flit = from p in PRODUCT LIST select p;

Categories

Resources