3

Something is bothering me about repository pattern

What is the actual purpose of a repository ? I understand it as a part of Domain.Model, something that provides means of executing commands on aggregates and that is it.

Now if you are using a generic base Repository which provides means for CUD you might say that you're domain is not generic so the repository is not generic and I agree but only from one point of view the queries being emitted and not the commands.

I fell that a generic repository eliminates the need for Domain.Repositories at least in the context of DDD mixed with CQRS (I know that I might sound controversial and it's exactly how I fell as well). But if you split your commands from your queries, then you will have WriteRepositories containing only CUD operations. Thus having lots of duplicates all over the place.

Imagine this

CustomerRepository : ICustomerRepository
{
    void Add(CustomerAggregate agg);
    void Update(CustomerAggregate agg);
}


BookRepository : IBookRepository 
{
    void Add(BookAggregate agg);
}


SubscriptionsRepository : ISubscriptionsRepository
{
     void Add(SubscriptionAggregate agg);
     void Update(SubscriptionAggregate agg);
     void Delete(SubscriptionAggregate agg);
}

...... another 5 repos

So does a generic repository makes sense in the context of DDD using CQRS pattern where you have Command.Stack + Query.Stack ?, and if so, does it eliminate the need for Domain.Repositories (command repositories) ?

4 Answers4

5

What is the actual purpose of a repository ?

Chapter 6 of Evans (the blue book) covers the repository pattern in considerable detail. Repositories "provide the illusion of an in memory collection...."

A REPOSITORY lifts a huge burden from the client, which can now talk to a simple, intention-revealing interface, and as for what it needs in terms of the model

They decouple application and domain design from persistence technology, multiple database strategies, or even multiple data sources.

It's not part of the domain model, and doesn't directly support command execution. Instead, it's an abstraction that separates the code that understands domain behaviors (via the API of the aggregate roots) from the code that understands how perform data lookup and convert between persisted representations and in memory representations.

I understand it as a part of Domain.Model, something that provides means of executing commands on aggregates and that is it.

Not really? The aggregates roots are part of the domain model, as are the factories that know how to assemble them.

But the repositories aren't really part of the domain model; the domain model doesn't use repositories at all; the application layer consumes them, the infrastructure layer provides implementations.

So does a generic repository makes sense in the context of DDD using CQRS pattern

Well, the guy who popularized the CQRS pattern wasn't a big fan of generic repository interfaces.

Community
  • 1
  • 1
VoiceOfUnreason
  • 52,766
  • 5
  • 49
  • 91
1

Not all domain entities can be deleted or updated. I would say that having a base repository containing the CUD operations from which you can then derive your own EntityRepository allowing only for what operations make sense to that specific Entity is a good approach.

0

You would use a generic repository if you have a problem which would benefit from it... otherwise don't use generic repository... you could also define a generic base repository and have your other repositories inherit the common functionalities from it:

public class RepositoryBase<TEntity> : IRepositoryBase<TEntity>
       where TEntity : class
{
    // generic add logic
    public virtual void Add(TEntity entity)
    {
        DbSet.Add(entity);
        Context.SaveChanges();
    }

    // generic update logic
    public virtual void Update(TEntity entity)
    {
        DbSet.Attach(entity);
        Context.Entry(entity).State = EntityState.Modified;
    }
}

Now, in your child repositories, you could override the generic definition... for example here, I want to define a repository for one of my aggregate roots, and I want it to override the Add logic... and inherit the exiting Update logic:

public class MyAggRootRepository<TEntity> : RepositoryBase<MyAggRoot>,
    IMyAggRootRepository<MyAggRoot>
{
    public override void Add(TEntity MyAggRoot)
    {
        if (MyAggRoot.Id > 0 )
        {
            throw new Exception("Invalid request, Id > 0 means model is already added.");
        }

        DbSet.Add(MyAggRoot);
        Context.SaveChanges();
    }

    // happy with the inherited Update logic
}

Again, the choice of generic repository is about the nature of your problem...

Hooman Bahreini
  • 14,480
  • 11
  • 70
  • 137
-1

I don't think that CQRS would necessarily have any real impact on the design of the repositories. You would still need to persist/retrieve your aggregates.

However, when using event-sourcing the picture changes somewhat as the event store will act as the repository for absolutely all aggregates.

Eben Roux
  • 12,983
  • 2
  • 27
  • 48