In order to use dependency injection in .NET Core, we've built a bunch of repository interfaces for our controllers to use for database interactions.
We have a EntityBase class that has some methods in it, and our generic repository interface uses that base class like: IRepository<T> where T : EntityBase.
I want to add a more specific TaggedEntityBase class that extends EntityBase to represent the fact that we have some Entities which we want to filter by tags. I want TaggedEntityBase to have an abstract property which I can use in my controller so that I can abstract out and reuse the filtering method.
So what I want is something like this, but I think I want ITaggedRepository to also inherit from IRepository so that a class implementing ITaggedRepository is guaranteed to have a ListAll method and a ListWithTags method:
public class EntityBase { }
public abstract class TaggedEntityBase : EntityBase
{
public string TagIDs { get; }
}
public interface IRepository<T> where T : EntityBase
{
IEnumerable<T> ListAll();
}
public interface ITaggedRepository<T> where T : TaggedEntityBase
{
IEnumerable<T> ListWithTags(System.Linq.Expressions.Expression<Func<T, bool>> predicate);
}
I'm fairly certain that I've just thoroughly confused myself by pursuing this line of thinking, but I'm not sure how to do what I really want here. I know I need to keep things abstract for dependency injection, but I feel like I'm butting up on the edge of what's possible with interfaces.
Is there a better line of thinking that will get me where I'm trying to go?
You can go ahead and inherit from IRepository<T>:
public interface ITaggedRepository<T> : IRepository<T> where T : TaggedEntityBase
{
IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate);
}
At some point you may into trouble if your TaggedEntity is not really an abstraction. Say you have NamedEntities also and some are Tagged.
Now you have a INamedRepository, ITaggedRepository and a INamedTaggedRepository (you'll run into similar issues on your base entity).
You could do a more trait like thing like:
public class EntityBase {}
public interface ITagged
{
string TagIDs { get; }
}
public interface INamed
{
string Name { get; }
}
public class Book : EntityBase, ITagged, INamed
{
public string TagIDs { get; set; }
public string Name { get; }
}
public interface IRepository<T> where T : EntityBase
{
IEnumerable<T> ListAll();
}
public interface IQueryTags<T> where T : ITagged
{
IEnumerable<T> ListWithTags(Expression<Func<T, bool>> predicate);
}
public interface IQueryByName<T> where T : INamed
{
T GetByName(string name);
}
public interface IBookRepository : IRepository<Book>, IQueryTags<Book>, IQueryByName<Book>
{
}
public class ConcreteBookRepository: IBookRepository
{
public IEnumerable<Book> ListAll()
{
throw new NotImplementedException();
}
public IEnumerable<Book> ListWithTags(Expression<Func<Book, bool>> predicate)
{
throw new NotImplementedException();
}
public Book GetByName(string name)
{
throw new NotImplementedException();
}
}
In the concrete implementation you could, through composition, use a ByNameQueryer, TagQueryer and some concrete Repository.
I don't really like generic repositories, so I tend to rename IRepository to IStore since it usually only contains the CRUD aspect typically.
Oh and then some entities you can't delete, some can't be updated. You will end up breaking that down to IAdd, IUpdate, IDelete etc. This is where you start to wonder if this was actually a good idea also ;-)
Related
partial class Repository<TEntity> : IRepository<TEntity> where TEntity : class
{
}
My generic repository implements a common set of methods for TEntity like
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public TEntity Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>()
}
which I can access like
Repository<User>().Get();
Many repositories does the same set of operation, so it is beneficial but now I want to extend Repository<User> to support some additional behavior.
partial class Repository<User> : IRepository<User>
{
public user DoMagicFunction()
{
}
}
so that I can use the repository like
Repository<User>().DoMagicFunction();
how can I extend the same generic class for Some Tentity to extend new behaviour instead of modifying it.
I could have done the same like creating another UserRepository to support new feature, but the accessor would become
UserRepository.DoMagicFunction();
but I want it to be like
Repository<User>().DoMagicFunction();
You can use an extension method:
public static class ExtensionMethods {
public static User DoMagicFunction(this Repository<User> repository) {
// some magic
return null; //or another user
}
}
This will thus add the function in a syntactically nice way to Repository<User> objects.
In case you want to support it not only for Users, but for subclasses of Users as well, you can make the function generic:
public static class ExtensionMethods {
public static TEntity DoMagicFunction<TEntity>(this Repository<TEntity> repository)
where TEntity : User {
// some magic
return null; //or another TEntity
}
}
C# has a language feature called Extension Methods, you probably are using them from the .NET framework without knowing (e.g. the linq extensions methods). It's common to extend your classes or even your interfaces with extension methods without breaking the functionality of your code. Here is an example for your case.
Suppose you have a generic IRepository interface:
public interface IRepository<TEntity> where TEntity : class, IEntity
{
IQueryable<TEntity> Entities { get; }
}
This interface adheres to the SOLID principles, especially the O and I principle.
Now suppose IEntity looks like this:
public interface IEntity
{
int Id { get; }
}
Now you could perfectly imagine an often reusable extension method like this:
public static class RepositoryExtensions
{
// similar to your MagicFunction
public static TEntity GetById<TEntity>(this IRepository<TEntity> repository, int id)
where TEntity : class, IEntity
{
return repository.Entities.Single(entity => entity.Id == id);
}
}
In a similar manner you could also extend your Repository class
public static class RepositoryExtensions
{
public static TEntity GenericMagicFunction<TEntity>(this Repository<TEntity> repository)
{
//do some stuff
}
}
You can now consume that like this:
var repository = new Repository<User>();
var user = repository.GenericMagicFunction();
You could also limit your extension method:
public static class RepositoryExtensions
{
public static User DoMagicFunction(this Repository<User> repository)
{
//do some stuff
}
}
But doing this will defeat it's purpose, you could rather just implement this in the Repository<User> class.
If your system and architecture uses Dependency Injection, you're probably injecting an IRepository<User> to your consuming classes. So the first or second extension method examples I've provided would make the most sense.
If you want to extend any repository you can do it like this.
public static class RepositoryExtension
{
public static void MagicMethod<TEntity>(this IRepository<TEntity> repo) where TEntity: class
{
....
}
}
For a specific repository (eg User repository) you can use a similar process
public static class RepositoryExtension
{
public static void MagicMethod(this IRepository<User> repo)
{
....
}
}
Extension methods are not the way to go, because the code that implements the method can only access public/internal members of the class they extend and you are likely to want your repository's DataContext to be private.
In my opinion, your approach needs to be changed slightly.
What if in the future you want to add a Delete method to your generic repository, but you have some entities that should never be deleted? You'll end up with an instance of a repository for something like PurchaseOrder that you'll either have to remember to never call delete on or you will have to create a descendant of Repository<T> that throws an InvalidOperationException if called. Both of which are poor implementations.
Instead, you should delete your IRepository<T> interface completely. Keep your Repository<T> class, but explicitly define a repository interface for every entity that only has the methods you require.
public class Repository<TKey, TEntity>......
{
public TEntity Get<TEntity>(TKey key)....
public void Delete(TEntity instance)....
...etc...
}
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
// Note: No delete is exposed
}
MyDependencyInjection.Register<IPurchaseOrderRepository, Repository<PurchaseOrder, int>>();
When you need additional methods on your repository you add them to your IPurchaseOrderRepository and create a descendant of Repository<T>
public interface IPurchaseOrderRepository {
PurchaseOrder Get(int orderNumber);
void DoSomethingElse(int orderNumber);
}
public class PurchaseOrderRepository: Repository<PurchaseOrder, int> {
public void DoSomethingElse(int orderNumber) {.......}
}
MyDependencyInjection.Register<IPurchaseOrderRepository, PurchaseOrderRepository>();
Extension method is a best choice for this case.
Note: I have not checked but you should check Dependency Injection still works well as normal.
You can use below code for testing:
public class Employee
{
}
public class User
{
}
public interface IRepo<TEntity> where TEntity : class
{
TEntity Get(int id);
DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate);
DbContext GetContext();
}
public class Repo<TEntity> : IRepo<TEntity> where TEntity : class
{
DbContext _context;
public TEntity Get(int id)
{
return _context.Set<TEntity>()
.Find(id);
}
public DbSet<TEntity> Get(Expression<Func<TEntity, bool>> predicate)
{
return _context.Set<TEntity>();
}
public DbContext GetContext()
{
return _context;
}
}
public static class RepoExtensions
{
public static ChangeTracker DoMagic(this Repo<User> userRepo)
{
return userRepo.GetContext().ChangeTracker;
}
}
public static class Test
{
public static void DoTest()
{
Repo<User> repoUser = new Repo<User>();
repoUser.DoMagic();
Repo<Employee> repoEmployee = new Repo<Employee>();
//repoEmployee.DoMagic();
}
}
I have completely re-written this hoping to make my question clearer. I have chosen the concept of services making use of repositories in my example code.
Example code:
class Program
{
interface IEntity
{
int Id { get; set; }
}
// Example entity could be:
class Book : IEntity
{
public int Id { get; set; }
}
class Magazine : IEntity
{
public int Id { get; set; }
}
interface IRepository<TEntity> where TEntity : class, IEntity
{
IEnumerable<TEntity> GetEntities();
}
interface IBooksRepository : IRepository<Book> { }
interface IMagazineRepository : IRepository<Magazine> { }
class DataStore<TEntity> where TEntity: class, IEntity
{
public IEnumerable<TEntity> GetFromStore()
{
throw new NotImplementedException();
}
}
abstract class RepositoryBase<TEntity> : IRepository<TEntity>
where TEntity : class, IEntity
{
DataStore<TEntity> _dataStore;
public RepositoryBase()
{
_dataStore = new DataStore<TEntity>();
}
public IEnumerable<TEntity> GetEntities()
{
return _dataStore.GetFromStore();
}
}
class BookRepository : RepositoryBase<Book>, IBooksRepository { }
class MagazineRepository : RepositoryBase<Magazine>, IMagazineRepository { }
abstract class ServiceBase<IEntityRepository, TEntity>
where IEntityRepository : IRepository<TEntity>
where TEntity : class, IEntity
{
IEntityRepository _repository;
public ServiceBase(IEntityRepository repository)
{
_repository = repository;
}
public IEnumerable<TEntity> GetEntitiesFromRepository()
{
return new List<TEntity>();
}
}
class BookService : ServiceBase<IBooksRepository, Book>
{
public BookService(IBooksRepository bookRepository)
: base(bookRepository)
{ }
}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>
{
public MagazineService(IMagazineRepository magazineRepository)
: base(magazineRepository)
{ }
}
static void Main(string[] args)
{
var aBookService = new BookService(new BookRepository());
var aMagazineService = new MagazineService(new MagazineRepository());
var books = aBookService.GetEntitiesFromRepository();
var magazines = aMagazineService.GetEntitiesFromRepository();
}
}
This all works fine and perhaps it is valid to ask why I want to change this. Mainly I am just curious if I can make this more neat. It is more a point of curiosity that one of functional correctness I suppose.
Both IBookRepository and IMagazineRepository know which concreate type they represent 'Book' and 'Magazine'
When I define my concreate services: BookService and MagazineService I have to specify the type as well as the interface:
class BookService : ServiceBase<IBooksRepository, Book>{}
class MagazineService : ServiceBase<IMagazineRepository, Magazine>{}
I wondered if I could simplify thier signatures as the Interfaces already know The type I am expecting Book or Magazine.
Can I extract the Entity Type from the inteface such that I no longer need to specify the type when creating concreate service types?
As I pondered this, I discovered a deeper issue with my knowledge of C#:
What exactly is the type of 'thing' that the generic system is looking for between those angle brackets: IEnumerable<TThisThing>.
When I look at intellisense is says T is the type of objects to enumerate.
So as an experiment I grabbed the type of MyType:
Type typeOfMyType = instanceOfMyType.GetType();
IEnumerable<typeOfMyType> enumerable = new List<typeOfMyType>(); //crude example.
Now of course this does not work. So what kind of thing is TThisThing that works between the angle brackets?
is there a way of extracting this information so that I can forgo the
inclusion of 'MyType' in the class definition and use the discovered
TMyType in the example method?
Yes, you simply need to define the generic type parameter in the methods name:
public IEnumerable<TMyType> GetMyTypes<TMyType>()
{
// get list of TMyType instances;
return list;
}
If you don't want to use a generic type parameter at all, you'll have to defer to reflection, and you won't be able to use a compile-time generic type such as returning an IEnumerable<T>.
So what kind of thing is TThisThing that works between the angle
brackets?
TThisThing should be a compile-time known type parameter. When you use Type typeOfMyType = instanceOfMyType.GetType();, the type of instanceOfMyType is only known at run-time.
For example:
var obj = new SomeClass<Foo>();
IEnumerable<Bar> bars = obj.GetMyTypes<Bar>();
Where Foo and Bar:
public class Foo { }
public class Bar { }
I am just starting in DDD and have a question regarding interfaces of objects and repositories. Suppose I have the following objects
public interface IPerson { ... }
public class Student
{
double gpa;
...
}
public class Teacher
{
double salary; ...
}
then I also have two repositories such as
public class StudentRepository :IRepository { public void Save(Student) }
public class TeacherRepository :IRepository { public void Save(Teacher) }
My question is, suppose I have a list of IPerson objects called persons, is there a way where I can just do something like repository.Save(persons) ? Without having to use reflection to figure out what type the IPerson actually is.
I currently have another class
PersonRepository :IRepository
{
public void Save(IPerson person)
{
if(Person is Student)
{
new StudentRepository.Save(person as Student);
}
else if(Person is Teacher)
{ ....}
}
}
Then I can call personRepository.Save(persons);
However this doesnt feel like an optimal way to structure things. How can I improve this design?
Thanks
EDIT:
What I'm looking for is, say I receive an IPerson object called person. I do not necessarily know what implementation it is, I just want to call repository.Save(person) and have it call the correct repository. Is there a way to do this without using some sort of switch statement with reflection?
Consider using generic repository
class Repository<T> :IRepository<T>
{
public void Save(T entity)
{
...
}
}
Usage
IRepository<Student> repo1 = new Repository<Student>();
repo1.Save(new Student());
IRepository<Teacher> repo2 = new Repository<Teacher>();
repo2.Save(new Teacher());
Next you can use IoC container and DI just to pass repositories around instead of creating them
At the top level, say in the main method or global.asax
IRepository<Student> studentRepo = IoC.Current.Resolve<IRepository<Student>>();
Later in a class that needs to save data, pass IRepository<Student> studentRepo into constructor
class Foo
{
private IRepository<Student> repo
Foo(IRepository<Student> repo)
{
this.repo = repo;
}
public void Save(Student s)
{
repo.Save(s);
}
}
EDIT
You can move a save operation to the IPerson<T>
class Person<T> : IPerson<T>
{
private IRepository<T> repo;
Person(IRepository<T> repo)
{
this.repo = repo;
}
public void Save()
{
repo.Save<T>();
}
}
So when you derive Teacher and Student from Person<T> you pass correspondent T, like
class Student : Person<Student>
{
private IRepository<Student> repo;
Person(IRepository<Student> repo):base(repo)
{
...
}
}
This shall give you the ability to work with List without Reflection or switch kung fu.
You can potentially have a method with C# generics
interface Repository<TEntity> where TEntity : class {
void Save(TEntity entity);
}
But I would discourage having generic (as in generalized, not C# generics) repositories. Repository interface should be domain driven and specific to your entity. Please consider this article by Greg Young.
It is also not clear why you have interfaces for you entities (IPerson). Interfaces are usually created at the seam of the application. Are you planning to have more than one implementation of IPerson?
Two possible approaches.
First, interfaces specific for domain types
interface IStudentRepository
interface ITeacherRepository
class StudentRepository : IStudentRepository
class TeacherRepository : ITeacherRepository
Second, a generic interface
interface IRepository<T>
class StudentRepository : IRepository<Student>
class TeacherRepository : IRepository<Teacher>
I want to design an interface has the function to do mapping from Entity object to Form object
public interface IFormToEntityMapper
{
TEntity Map(TForm tForm);
}
and vice versa.
public interface IEntityToFormMapper
{
TForm Map(TEntity tEntity);
}
I have the question if I should define these two functions in one interface and separate them to different interfaces. If I put them into one interface, does that violate the single responsibility principle?
One option is to use Generics for the Interface:
public interface IMapper<TSource, TDestination> {
public TDestination Map(TSource source);
}
public class FormToEnityMap : IMapper<Form, Entity> {
public Entity Map(Form source){
}
}
public class EntityToFormMap : IMapper<Entity, Form> {
public Form Map(Entity source) {
}
}
I have the following domain object:
public class DomainObject<T,TRepo>
where T : DomainObject<T>
where TRepo : IRepository<T>
{
public static TRepo Repository { get;private set; }
}
A repository interface:
public interface IRepository<T> //where T : DomainObject<T> // The catch 22
{
void Save(T domainObject);
}
An implementation of the 2:
public class User : DomainObject<User,MyRepository>
{
public string Name { get;private set;}
}
public class MyRepository : IRepository<User>
{
public List<User> UsersWithNameBob()
{
}
}
So adding another method that isn't inside IRepository.
I want to enforce the repository as an IRepository while above it could be any type.
A small sidenote: I'm writing this for small systems with very few domain objects. I'm not looking to create anything that uses IoC, but rather something that is easy and simple to consume.
Thanks
Your implementation of DomainObject is only specifying one generic type argument instead of two. Why isn't it:
public class User : DomainObject<User, MyRepository>
{
public string Name { get;private set;}
}
If that doesn't work, could you explain in what way it doesn't do what you need?
Not exactly sure what you want, but something like this compiles:
public class DomainObject<T, TRepo>
where T: DomainObject<T, TRepo>
where TRepo: IRepository<T, TRepo>
{
public static TRepo Repository
{
get;
private set;
}
}
public interface IRepository<T, TRepo>
where T: DomainObject<T, TRepo>
where TRepo: IRepository<T, TRepo>
{
void Save(T domainObject);
}