Matteo Migliore
Matteo Migliore

Reputation: 923

Projections from Repository in classic and DDD perspective

I would an opinion about how you see the Repository pattern.

In the "old" Domain conception (for example from P of EAAA) the repository should be like an "in memory collection", so it should returns always the same type, so if you need a projection you have to make it out, so the projection will be made in the service layer for example, right? Or is possible to make it directly into the "Domain" project?

E.g.

public class CustomerRepository
{
    //Constructor accepts an IRepository<Customer>

    public IQueryable<Customer> GetAllDebtors()
    {
        //Use IRepository<Customer> here to make the query
    }
}

Instead, in DDD, the repository, especially combined with CQRS, can return directly the projected type because the repository becomes a denormalization service, right?

E.g.

public class CustomerDenormalizer
{
    //Constructor *could* accept an IRepository<Customer>

    public IQueryable<Debtor> GetAllDebtors()
    {
        //Use IRepository<Customer> here to make the query and the projection
    }
}

Upvotes: 2

Views: 3067

Answers (4)

Chalky
Chalky

Reputation: 1642

  • Don't have generic Repository.
  • Don't have IQueryable.
  • Have ICustomerRepository.
  • Have your specific implementation of CustomerRepository leverage all the bells and whistles of the underlying storage system.
  • Have repository return projections.

    public Interface ICustomerRepository {

    public IEnumerable< Customer> GetAllCustomer()

    public IEnumerable< Debtor> GetAllDebtors()

    public IEnumerable< CustomerSummary> GetCustomerSummaryByName(string name)

    public IEnumerable< CustomerSummary> GetCustomerSummaryById(string id) }

Upvotes: 0

Giacomo Tesio
Giacomo Tesio

Reputation: 7210

In the "old" Domain conception (for example from P of EAAA) the repository should be like an "in memory collection", so it should returns always the same type, so if you need a projection you have to make it out, so the projection will be made in the service layer for example, right?

In my own solutions, I keep distinct the domain model (that is an C# expression of the language I learned from the domain expert, almost an internal DSL) and the applicative concerns related to the domain (such as repositories, that cope with the application need of persistence). This means that they are coded in different projects.

In such a structure, I've tried two different approaches: queryable repositories and custom ones.

  • Repositories that implement IQueryable have worked very well for developers using the domain to build UI or services exposed to third parties, but required a lot of work in infrastructure. We used different approaches on this side, from Linq2NHibernate to re-linq, each with pros and cons, but each one quite expensive. If you plan to use this technique, define good metrics to ensure that the time you save during application development worth the time you have to spend on custom infrastructure.
  • Custom repositories (those that expose methods returning IEnumerables) are much easier to design and implement, but they require more effort for UI and service's developers. We also had a case where using a custom repository was required by domain rules, since the query objects used to obtain results were specifications that were also part of the ubiquitous language and we were (legally) required to grant that the method used to query was the same used to express such value and predicate.
    However, in custom repositories, we often expose projective methods too.

Or is possible to make it directly into the "Domain" project?

It's possible, but when you have many different (and very complex) bounded contexts to work with, it becomes a pain. This is why I use different projects for the domain classes expressing the ubiquitous language and the classes that serve applicative purposes.

Instead, in DDD, the repository, especially combined with CQRS, can return directly the projected type because the repository becomes a denormalization service, right?

Yes, they can.
That's what we do with custom repositories, even without CQRS. Furthermore, even with some repository implementing IQueryable, we occasionally exposed methods that produce projections directly.

Upvotes: 1

guillaume31
guillaume31

Reputation: 14080

Saying that the Repository in its "original form" has to return only objects of the same entity type is somewhat exaggerated. At all times people have been including Count() methods or other calculations in their Repositories for instance - and that's something that was documented even back in Evan's blue book.

On the other hand, I'm not sure what you mean by "denormalized types" but if that's types that borrow from several different entities to expose their data as is or consolidated, or expose partial views of single domain entities, I tend to think it's not the Domain any more. Oftentimes it turns out they serve application-specific purposes such as generating Excel reports or displaying statistics or summary screens.

If this is the case, and for performance reasons I want to leverage the DB directly instead of relying on the Domain, I prefer to create a separate project where I place all this "reporting" related logic. Never mind if you still name your data access objects Repositories in there (after all, they are also illusions of in-memory collections, only collections of other types).

Upvotes: 1

eulerfx
eulerfx

Reputation: 37739

IMO, the correspondence with an "in-memory" collection is overemphasized. A repository shouldn't hide the fact that it encapsulates some heavy IO - that would be a leaky abstraction. Furthermore, IQueryable<T> is also a leaky abstraction since hardly any provider will support all the operations. I'd suggest delegating as much of the projecting as possible to the database, because it is quite good at it.

A projection in CQRS is somewhat different. It is usually implemented as an event consumer which updates a datastructure stored in some underlying storage mechanisms, which could itself be SQL server, or a key-value store. The central difference is that, in this case, a projection response to events from a message queue. These events could be coming from external systems.

Upvotes: 1

Related Questions