Generic repository, DI, Aggregation Roots

2019-05-29 02:19发布

Having a generic repository like

public class Repository<T> 
    where T: Entity<T> 
{ 
    /*anything else*/ 
}

should concrete repositories per agregation root like

class ProductRepository : Repository<Product> 
{
} 

class CategoryRepository : Repository<Category> 
{ 
}

be created?

Also how do I use DI (Ninject) with generic implementation of repository.

Samples are apreciated!

Thanks!

1条回答
Root(大扎)
2楼-- · 2019-05-29 02:32

I see a lot of misuse of generics in the questions in SO and while it does not necessarily refer to your question (although it will help to clarify), I think once for all write a summary here.

Generics is a typeless reuse of the behaviour (almost, since you can limit the types using restrictions). If a behaviour is shared by all types (or those limited to restrictions) you use the generics.

However if implementation of each generic type needs to be individually implemented, then using generics does not help and is reduced to a decoration - and for me it is bad design.

OK, let's have an example:

interface IConverter<T1, T2>
{
    T1 Convert(T2 t2);
}

This looks like a good generics (converting one type to another), but I have to implement all such combinations of types as different converters. And a IConverter<Apple, Orange> does not make any sense. Hence generics here is misleading and BAD.

Now going back to repositories. There are 100s of articles on this particular issue (lots of controversies) but this is personal my take:

Usually it is not recommended to use generic repositories. However, in my personal experience I use generic repository to implement common stuff (implemented by a base repo) and then use individual ones if there is any additional:

interface IRepository<T>
{
    T GetById(int id);
    IEnumerable<T> GetAll();
    void Save(T t);
}

class BaseRepository<T> : IRepository<T>
{
   ... // implement common methods
}

interface IProductRepository : IRepository<T>
{
    IEnumerable<T> GetTop5BestSellingProducts();    
}

class ProductRepository : BaseRepository<T>, IProductRepository 
{
    ... // implement important methods
}

NOTE

Some believe repository must allow for criteria to be passed to the repository (Eric Evans DDD book) but I again do not feel I have to agree to that. I prefer a domain-significant declaration on the repository (e.g. GetTopFiveBestSellingProducts or GetTopBestSellingProducts) unless there are 100s of such like in a report writer which is only 1% of cases.


Second question:

I do not use Ninject but for any DI, here is how you do it

 // PSEUDOCODE !!!
 container.Register<IProductRepository , ProductRepository>(); 

depending on DI framework, it can be slightly different.

查看更多
登录 后发表回答