How do read-only database views fit into the repository pattern?
Asked Answered
I

3

23

Example: Your database has a SQL view named "CustomerOrdersOnHold". This view returns a filtered mix of specific customer and order data fields. You need to fetch data from this view in your application. How does access to such a view fit into the repository pattern? Would you create a "CustomerOrdersOnHoldRepository"? Is a read-only view such as this considered an aggregate root?

Imminence answered 9/9, 2011 at 18:28 Comment(0)
C
34

I would prefer separating the read repository, preferably even change its name to Finder or Reader, the repository is meant for Domain usage not for querying read-only data, you can refer to this article and this which explains the usage of Finder separated form repository.

I would recommend also the separating of read model from write model architecture CQRS and there

This architecture allows you to separate the read model from write model even in terms of data storage and the use of event sourcing.

For a middle solution you can utilize some CQRS concepts without the complexity of separating database by just separating repository from finders, read this post

for a sample of this type of solution (use the same database but separating finders form repositories) check this sample

Cohlette answered 11/9, 2011 at 12:5 Comment(5)
I think this is the best answer. This type of data/objects are nothing to do with the domain, and as Mohamed has pointed out, the term repository is associated with aggregates/domain/transactions, so the use of this term could be misleading. CQRS is aimed at solving this exact issue. I asked a similar question a while back: #2098612Despoil
Great answer due to the great links. This helped me view my code from a different and clearer perspective.Cuthbert
If you have a Finder, how do you name the "Saver"? Repository? But then a repository should be able to access the data AKA "query"... how to address this?Diapophysis
Name is Repository. The repository does not query (as in search) it only gets object by Id. Where Finder will do all fancy querying. Also if you do follow CQRS and have different read model, the Finder will return a different object anyway where the Repository will return the domain object.Cohlette
@MohamedAbed you "this article" and "this" links are dead.Heaney
H
0

I think that it is fine to have a separate repository like "CustomerOrdersOnHoldRepository". The interface of the repository will reflect the fact that the objects are readonly (by not defining Save/Add/MakePersistent method).

From How to write a repository:

... But there is another strategy that I quite like: multiple Repositories. In our ordering example there is no reason we can have two Repositories: AllOrders and SurchargedOrders. AllOrders represent a list containing every single order in the system, SurchargedOrders represents a subset of it.

I would not call returned object an Aggrgate Root. Aggregates are for consistency, data exchange and life cycles. Your objects don't have any of these. It seems that they also can not be classified as Value Objects ('characteristic or attribute'). They are just standalone classes.

Harms answered 9/9, 2011 at 19:3 Comment(2)
I was leaning toward giving the view its own repository, however, it is my understanding that repositories operate upon aggregate roots only (thinkddd.com/glossary/aggregate-root).Imminence
This rule is about avoiding direct access to internal parts of aggregate. You don't have these internal parts, just like you don't have any invariants and lifecycle. It is ok to return these objects from repository. Call them Aggregate Roots if you like but that can be a bit misleading.Harms
A
0

Your read-only data would be considered Value Objects in the DDD world.

I typically place access methods for value objects in existing repositories until such time that it makes sense to create a separate repository. It's similar to a method that might return a static list of states to be used on an address form:

IAddressRepository
{
  Address GetAddress(string addressID);

  List<string> GetStates(string country);
}
Additional answered 9/9, 2011 at 20:18 Comment(1)
So in your scenario, if I have a CustomerRepository or an OrderRepository I would add a method to one of these repositories? i.e. ICustomerRepository.GetCustomerOrdersOnHold(args) or IOrderRepository.GetCustomerOrdersOnHold(args)?Imminence

© 2022 - 2024 — McMap. All rights reserved.