2

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!

lexeme
  • 2,915
  • 10
  • 60
  • 125

1 Answers1

5

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.

Aliostad
  • 80,612
  • 21
  • 160
  • 208
  • Thanks! And one more thing I want to ask.. At the moment my domain objects (entities) are anemic. Why is this bad? How do I refactor model to be not anemic. For example `Post` - as an aggregation root - holds collection of feedbacks which is a `HashedSet`. So it is possible to add feedbacks using the property's method `Add()`. – lexeme Jan 04 '12 at 12:40
  • Anemic is not bad AFAIK. I use it all the time!! This is the separation which is needed. Consider client and server using entities and you have `Add` on the entity so you have to ship all other dependencies for saving, ... to the client. We need this separation. – Aliostad Jan 04 '12 at 12:50
  • I think you mean `container.Register();` instead of `container.Register>();`. – Steven Jan 04 '12 at 15:25
  • Thanks Steven. Well, it is different for each DI, and I have used Windsor and AutoFac, and they are opposite order. Autofac uses `builder.RegisterType().As();`. I changed it for clarity, and in fact I meant `IRepository` – Aliostad Jan 04 '12 at 16:12
  • @helicera This is a nice article about Anemic domain model: http://martinfowler.com/bliki/AnemicDomainModel.html The problem is that you're having a domain model that consists only of get/set and no real behavior. So you don't have any profit of using a domain model but you have all the problems (like object-relational mapping) – Wouter de Kort Jan 04 '12 at 16:25
  • @WouterdeKort This is where I do not feel like I have to agree with someone like Fowler - the daddy of the design. Separating these concerns goes against the principals of OO design, but so is the IoC. These are lessers of evil. SOLID is more important that early 2000 design concepts - although that one is also very old. – Aliostad Jan 04 '12 at 16:52
  • @Aliostad Fowler's point is that if you use an anemic domain model, you could have also used a typed Dataset without losing any functionality and gaining a lot of performance. http://www.methodsandtools.com/archive/archive.php?id=97 contains a good intro to DDD and shows why you should aim for a not-anemic domain model – Wouter de Kort Jan 04 '12 at 16:57
  • @WouterdeKort I do not agree (who am I?! Well, I do have my own opinion :) I still put some behaviour in the entity such a calculated properties. I will read your link. Thanks – Aliostad Jan 04 '12 at 17:11
  • @Aliostad I'm not totally sure if where discussing the same point. A generic repository which only takes criteria objects vs repository with specific methods is another discussion then anemic domain model vs domain model Btw, this http://blog.lowendahl.net/?tag=entity-framework is a nice post about a criteria implementation of a repository – Wouter de Kort Jan 04 '12 at 17:14
  • @WouterdeKort yes, that was (ie criteria) to address another point which comes up often. – Aliostad Jan 04 '12 at 17:23
  • Comment by AgentFire: Don't you mean `interface IProductRepository : IRepository` and `class ProductRepository : BaseRepository` – StuartLC Nov 16 '12 at 13:06