I have read a bit about constraints and am trying to implement it in my repository pattern.
I want something like the below but can't quite get it to compile.
public interface IRepository<T>
{
void GetAllData<T>();
}
//This needs to inherit from IRepository
//T has to be a model class
//V has to be a class that implements IEmployeeRepo
public interface IEmployeeRepo<T, V> where V : EmployeeRepo where T : class : IRepository<T>
{
void DoSomethingEmployeeRelated();
}
//Dont think this inheritance is correct
public class EmployeeRepo<Employee, this> : IEmployeeRepo
{
}
//My example model class
public class Employee
{
public string Name {get;set;}
}
Not sure why you have two type parameters on the Repository - what is the point?
*Here is the classic example of a .NET Repository using Generics: *
*First, the Repository Interface: *
public interface IRepository<T> where T : class
{
T FindSingle(Expression<Func<T,bool>> predicate);
IQueryable<T> FindAll(); // optional - matter of preference
void Add(T entity);
void Remove(T entity);
}
*Second, the Generic Repository Implementation (EF as the example): *
public abstract class GenericRepository<T> : IRepository<T>
{
private IObjectSet<T> _ObjectSet; // get this in via DI (for example)
public T FindSingle(Expression<T,bool>> predicate)
{
return _ObjectSet.SingleOrDefault(predicate);
}
// you can figure out how to do the other implementation methods
}
*Then, the Specific Repository (you should have one per aggregate root, and also an interface for each specific repository detailing specific methods): *
public EmployeeRepository : GenericRepository<Employee>, IRepository<Employee>
{
// all regular methods (Find, Add, Remove) inherited - make use of them
public Employee FindEmployeeByName(string name)
{
return FindAll().SingleOrDefault(x => x.Name == name);
// or you could do: return FindSingle(x => x.Name == name);
}
}
Usage:
IRepository<Employee> repository = new EmployeeRepository<Employee>();
Don't go out looking to go too crazy with generics - the only one you need is to constrain the Repository to be used by a entity that is encapsulated behind the Repository.
I simply use where T : class.
Other's use where T : IDomainAggregate or similar, to put constraints on the actual type of entity which is allowed.
In this situation i usually have a base repo class that implements IRepository<>, and is typed to a base Model class.
public interface IRepository<T> where T : IModel
{
void GetAll<T>();
void GetById<T>(int id);
}
public interface IEmployeeRepo<T> : IRepository<T> where T : IModel
{
void DoSomethingEmployeeRelated();
}
public class BaseRepo : IRepository<T> where T : IModel
{
public void GetAll<T>()
{
}
public void GetById<T>(int id)
{
}
}
public class EmployeeRepo : BaseRepo<Employee>, IEmployeeRepo<Employee>
{
public void DoSomethingEmployeeRelated()
{
}
}
//My example model class
public class Employee : IModel
{
public int Id {get;set;}
public string Name {get;set;}
}
Try this;
public interface IRepository<T>
{
void GetAllData<T>();
}
//This needs to inherit from IRepository
//T has to be a model class
//V has to be a class that implements IEmployeeRepo
public interface IEmployeeRepo<T, V> : IRepository<T> where V : EmployeeRepo where T : class
{
void DoSomethingEmployeeRelated();
}
//Dont think this inheritance is correct
public class EmployeeRepo : IEmployeeRepo<Employee, EmployeeRepo>
{
public void DoSomethingEmployeeRelated()
{
}
public void GetAllData<Employee>()
{
}
}
//My example model class
public class Employee
{
public string Name {get;set;}
}
Related
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.
I hv two entities, USER and Document. both have their own interface Iuser and I Document.
public class UserRepository : IUserRepository<UserRepository>
{
public string GetUser()
{
return "Akash";
}
}
public interface IUserRepository<T> : IRepository<T> where T : class
{
string GetUser();
}
public class DocumentRepository : IDocumentRepository<DocumentRepository>
{
public string GetDocument()
{
return "Akash";
}
}
public interface IDocumentRepository<T> : IRepository<T> where T : class
{
string GetDocument();
}
Below is the base interface. All repo interfaces implement this base interface. It is empty ( on purpose) as I just want to store all repo class object in this IRepository interface variable.
public interface IRepository<T> where T : class
{
}
and than, in my UOW ( unit of work ) class, I am creating the repo instance as follows,
public IRepository<UserRepository> UserProfile
{
get
{
return GetRepository<UserRepository>();
}
}
private IRepository<T> GetRepository<T>() where T : class, new()
{
return (IRepository<T>)new T();
}
Now the problem is: repo object does not have the methods implemented in each repo class. It is obvious as I am type casting my repo object with IRepository interface which does not have any methods. I am looking for a work around. my purpose is to store all repo object in IRepository variable. Kindly suggest. This is typical OOP's issue.
I'm trying to implement the best code re-usability. The problem is that I can't access the base method located in the Base Abstract class form the Main Program through the repository.
If you go through the example below you will see a sample code of my situation.
So my question is how can I access methods located in the base abstract class from the main program.
Classes/Interfaces
public abstract class BaseEntity
{
public override abstract String ToString();
}
public abstract class BaseClass<T> where T : BaseEntity
{
public T GetById(int id)
{
//Dummy Code
return new T();
//
}
}
public interface IFooRepository
{
IList<Foo> GetOrderedObjects();
}
public interface FooRepository : BaseClass<Foo>, IFooRepository
{
public IList<Foo> GetOrderedObjects()
{
//GetById method is accessible from the repository - Fine
var obj = this.GetById(5);
//Dummy Code
return new List<Foo>();
//
}
}
//Main App
public class void Main()
{
private IFooRepository _fooRepository;
public void ProgramStartsHere()
{
//This is ok.
var list = _fooRepository.GetOrderedObjects();
//Problem is here - GetById method is not accessible from the main program through the FooRepository
var obj = _fooRepository.GetById(10);
}
}
GetById isn't defined in the interface
I would make an
public interface IBaseRepository<T> where T : BaseEntitiy {
T GetById<T>(int id);
}
Then BaseClass implements IBaseRepository<T>
and IFooRepository inherits from IBaseRepository<Foo>
EDIT :
A full example, similar to #Olivier J-D one, with idea (maybe wrong), that GetOrderedObject may be same for all your entities.
public abstract class BaseEntity
{
public override abstract String ToString();
}
//all generic methods
public interface IRepositoryBase<T>
where T : BaseEntity, new()
{
T GetById(int id);
IList<T> GetOrderedObjects();
}
//all methods specific to foo, which can't be in a generic class
public interface IFooRepository :IRepositoryBase<Foo>
{
void Update(Foo model);
}
//implementation of generic methods
public abstract class BaseClass<T> : IRepositoryBase<T>
where T : BaseEntity, new() // ===> Add new() constraint here
{
public T GetById(int id)
{
return new T();
}
public IList<T> GetOrderedObjects() {
var obj = this.GetById(5);
//Dummy Code
return new List<Foo>();
//
}
}
//implementation of Foo specific methods
public class FooRepository : BaseClass<Foo>, IFooRepository
{
public void Update(Foo model) {
//bla bla
}
}
Add a new Interface which declares the GetById method and let IFooRepository and BaseClass<T> inherit from it. You will have to add a generic type parameter to IFooRepository as well. (I renamed IFooRepository to IRepository<T>, since it is generic now.)
public abstract class BaseEntity
{
public override abstract String ToString();
}
public interface IRetriever<T>
where T : BaseEntity, new()
{
T GetById(int id);
}
public interface IRepository<T> : IRetriever<T>
where T : BaseEntity, new()
{
IList<T> GetOrderedObjects();
}
public abstract class BaseClass<T> : IRetriever<T>
where T : BaseEntity, new() // ===> Add new() constraint here
{
public T GetById(int id)
{
return new T();
}
}
public class FooRepository : BaseClass<Foo>, IRepository<Foo>
{
public IList<Foo> GetOrderedObjects()
{
var obj = this.GetById(5);
return new List<Foo>();
}
}
This will work fine then
IRepository<Foo> _fooRepository = new FooRepository();
var list = _fooRepository.GetOrderedObjects();
var obj = _fooRepository.GetById(10);
Your _fooRepository inherits from IFooRepository, not FooRepository, so it doesn't have access to GetById(10);
You must expose the GetById method in your repository interface.
public interface IFooRepository
{
IList<Foo> GetOrderedObjects();
Foo GetById(int id);
}
Alternatively you can use a type parameter constraint, as stated by Raphaƫl Althaus
IFooRepository doesn't inherit from BaseClass, so you have to cast _fooRepository to FooRepository. Then you can access GetById()
Cast it to the base class.
var obj = ((BaseClass<Foo>)_fooRepository).GetById(10);
I have an application that is structured as an service layer wich uses a repository layer for persistence.
I'm trying to create a generic controller class to reuse shared behavior but I'm having trouble trying to set the generic parameters. The following code:
public class BusinessEntity
{ }
public class Person : BusinessEntity
{ }
public interface IRepository<T> where T : BusinessEntity
{ }
public interface IService<T, R>
where T : BusinessEntity
where R : IRepository<T>
{ }
public partial interface IPersonRepository : IRepository<Person>
{ }
public interface IPersonService : IService<Person, IPersonRepository>
{ }
public abstract class BaseController<X, Y>
where X : BusinessEntity
where Y : IService<X, IRepository<X>>
{ }
public class PersonController : BaseController<Person, IPersonService>
{ }
fails at compilation with
The type ConsoleApplication.IPersonService cannot be used as type parameter Y in the generic type or method ConsoleApplication.BaseController<X,Y>. There is no implicit reference conversion from ConsoleApplication.IPersonService to ConsoleApplication.IService<ConsoleApplication.Person,ConsoleApplication.IRepository<ConsoleApplication.Person>>
this works
public interface IPersonService : IService<Person, IRepository<Person>>
but I lose the custom repository
There is a way to make the compiler realize IPersonRepository is an IRepository<Person>?
public class BusinessEntity
{ }
public class Person : BusinessEntity
{ }
public interface IRepository<T> where T : BusinessEntity
{ }
public interface IService<T, R>
where T : BusinessEntity
where R : IRepository<T>
{ }
public partial interface IPersonRepository : IRepository<Person>
{ }
public interface IPersonService : IService<Person, IPersonRepository>
{ }
public abstract class BaseController<X, Y, Z>
where X : BusinessEntity
where Y : IService<X, Z>
where Z : IRepository<X>
{ }
public class PersonController : BaseController<Person, IPersonService, IPersonRepository>
{ }
To address your comment:
IPersonService can extend the base service class to add custom facilities, like FindPersonsUnderAge(). For this it requires a custom repository. Actually LINQ avoids a lot of custom repository code, but sometimes they are required.
Couldn't IPersonService do that without requiring the repository type to be a type parameter? For example:
public interface IService<T> where T : BusinessEntity { }
public interface IPersonService : IService<Person>
{
IEnumerable<Person> FindPersonsByAge(double minAge, double maxAge);
}
public class Service<T, R> : IService<T>
where T : BusinessEntity
where R : IRepository<T>
{ }
public class PersonService : Service<Person, IPersonRepository>, IPersonService
{ }
Thanks to sll for pointing me in the right direction
public interface IService<T, out R>
where T : BusinessEntity
where R : IRepository<T>
{ }
does the trick
I have a generic repository as like that
public class Repository<T> : IRepository<T> where T: class
{
DataContext _db;
public Repository()
{
_db = new DataContext("connection string");
}
System.Data.Linq.Table<T> GetTable
{
get { return _db.GetTable<T>(); }
}
public T GetBy(Func<T, bool> exp)
{
return GetTable.SingleOrDefault(exp);
}
....
}
Is it possible to add a generic method to this repository to check for the existence of any entity like that:
public bool IsExisted(T entity)
{
...
}
it is easy to write it in any repository
_productRepository.GetBy(p => p.Id == 5 // or whatever);
where the productRepository like this:
public class ProductRepository : Repository<Product>
{
public ProductRepository()
: base()
{
}
}
I came to this since i always want to check for the existence of an entity alot, so i don't need to write the same method in all repositories.
If all your entities have for example a property Guid Id you can create the following interface for your entities:
public interface IEntity
{
Guid Id { get; set; }
}
And restrict your Repository class to it:
public class Repository<T> : IRepository<T>
where T : class, IEntity
{
....
}
You can then define the following function in your base repository:
public bool Exists(T entity)
{
return GetTable.Any(e => e.Id == entity.Id);
}