If I understand correctly CQRS is about dividing write and read responsibilities. So I can use repositories in my write model, for example var user = repository.GetUserById(); - this will get the user by id and then repository.UpdateUser(user); will update the user with changed properties. In the read model we can construct more complex DTO's:
public class UsersReadModel
{
private IMyContext context;
public UsersReadModel(IMyContext context)
{
this.context = context;
}
public ComplexUserDTO GetComplexUser(ISelectQuery query)
{
ComplexUserDTO user = new ComplexUserDTO();
// get all user properties, GetUser by id
user.UserDTO = context.Users.Where(d => d.UserId == query.UserId).ProjectTo<UserDTO>().FirstOrDefault();
//here I don't need everything from PoliciesTable, I just need two columns, so I use anonymous object
var policieObject = context.Policies.Where(f => f.BasePolicyId == query.PolicyId).Select(s => new { s.PoliciesNames, s.Clients.Select(d => d.ClientNames).ToList() }).FirstOrDefault();
user.PoliciesNames = policieObject.PoliciesNames;
user.ClientsNames = policieObject.ClientsNames;
return user;
}
}
So in my Write model, I get user by id from my repository, because i don't need to map it to DTO, and in my read model I use GetUser by id, but I map it to DTO, because I need it in that way. Isn't this code repeat(if I want to change getting user by id i'll have to change it in both places)? Can I use repositories in my read model? In this case I'll have to use both repositories and context(for the anonymous object, and selecting part of table columns) in UsersReadModel.
If your domain is very simple then the Write and the Read will be very similar and a lot of cod duplication will occur. In fact, this works in reverse as well, if your Write model is very similar to the Read model then you could implement them as CRUD and you don't necessarily need CQRS.
Can I use repositories in my read model?
You can have anything you want on the Read side; the two sides are separated from many points of view.
In CQRS there are many cases when code duplication occurs. Don't be afraid of that. You could extract that in shared classes.
P.S.
You should have a Read model for every use case, not for every Write model. If you have a 1:1 correspondence from Write to Read then this could also means that you should have implemented this using CRUD.
P.S. I like to use CQRS even if the domain is simple as I like to have very optimized Read models (different persistence type, no JOINS, custom data sharding etc).
There are a few things to look at here. From your description, it doesn't sound like there is a separation between the read and write models. Remember, they have very different purposes.
CQRS leans heavily on domain-driven design principles. A key principle is the encapsulation of your domain objects.
As a result, you wouldn't expect a domain object to have 'properties' on it (especially not setters). It may have ID for example but not much else. This is becuase it's role is to protect invariants within its self. Not something you can do easily if you have setters.
I would also argue that a domain object shouldn't really have getters except for id. If you have a good read model there is little need for them and may encourage incorrect use of the object. There are times when this idea can be relaxed a little. Although I can't think of one right now.
As a result, a repository for a domain object can be very simple. GetById and Save (unless you are using event sourcing but that's another topic).
The Read model, on the other hand, should be shaped to serve the UI. Each model is likely to have a mix of data from various sources. For example, you are likely to want to see a users details in context or their activities or orders or value to the company or whatever the purpose of the application is.
This explanation of the typical structure of a CQRS application may be helpful: CQRS + Event Sourcing - A Step by Step Overview
And this may give you some insight into creating domain objects: Aggregate Root - How to Build One for CQRS and Event Sourcing
Hope this helps.
If I understand correctly CQRS is about dividing write and read responsibilities.
Closer to say that it is about having data models that are designed for the use cases that they support.
We have Truth, and that truth has multiple representations.
The trick is that the representations don't need to be coupled in time -- we can update the "book of record" representation now, and the representations we use to support queries eventually.
Can I use repositories in my read model?
Absolutely. There's no magic.
Udi Dahan would probably suggest that you be thinking about different repositories, or perhaps more precisely methods on your repositories that provide different explicit representations of the read model depending on what you are doing. Each method loads the representation that you need for that particular use case.
Related
According to DDD for each aggregate i have repository. Let's take an example:
Client (model aggregate) > ClientRepository
Visit (model aggregate) > VisitRepository
Now phisicly i have association table in database which connects Client and Visit because clients could have many visists.
The question is: Should i create separated model like: ClientVisit which also would be an aggregate:
public class ClientVisit
{
int clientId;
int visitId;
}
Also s repository like ClientVisitRepository which could reference/use ClientRepository and VisitRepository.
Or is it enough to stick with e.g CLientRepository and get data from there without additionality model and repository
Modification to the post:
Instead of Visit (wrong example) - let's replace by Car therefore each client can have many cars. We would have also unique transactionNumber so:
Client (model aggregate) > ClientRepository
Car (model aggregate) > CarRepository
Should then i then create aggregate such as:
public class ClientCar
{
int clientId;
int visitId;
int transactionNumber;
}
and ClientCarRepository?
No, don't use a different repository for each entity or aggregate. You are not applying DDD completely in your modelling. You have to focus on the Ubiquitous language. Let me explain.
Repositories are meant to be nothing more than serializers and de-serializers for your entities and aggregates. There shouldn't be an intentional 1-to-1 between them. In fact, most of the time you won't have the 1-to-1. In my code, I tend to scope repositories to the bounded context or to a subcontext.
Take a trivial example: A blogging application. I might have a repository that can persist a comment. Persisting the comment means saving the comment itself and updating User's comment count. The Save(Comment comment, Usr usr) method will make two calls to my persistence mechanism to update the individual Entities or Aggregates.
Repository, in the sense of domain driven design, is a life cycle management pattern. See chapter 6 of the "blue book".
It's purpose is to isolate from our application code the strategy we are using to store and retrieve aggregate roots. That's important, because the aggregate roots are the only parts of the domain code that our application code talks to directly.
From this, it follows that you don't need a repository for the client car relation unless it is the root of its own aggregate.
Figuring out whether this relation should be in its own aggregate or not is a matter of domain analysis -- you're going to have to dig into your specific domain to figure out the answer. For something like a car rental domain, I would guess that you'll want this relation, and the information associated with its life cycle, to be in a separate aggregate from the car or the customer. But I wouldn't feel confident in that guess until I had worked through a few edge cases with the domain experts.
Whether you treat an entity as aggregate root, thereby introduce a corresponding repository, depends on your domain or its ubiquitous language. One of the key indicators of aggregates is that they encapsulate important domain operations.
Hard to be precise without knowing your domain, however, in your example, Client seems to be a more natural candidate for an aggregate: a client may own new cars, get rid of a few, etc; the corresponding operations (i.e. adding cars or removing cars) fit naturally into client.
ClientCar (or ClientVisit), on the other hand, doesn't seem to have any purpose other than retrieving cars owned by a client. For this purpose, navigating the entity should suffice, no aggregate is necessary. Your Client repository may introduce a method for this purpose like the following:
public interface ClientRepository
{
Client findById(String clientId);
void store(Client client);
IList<Cars> carsOwnedBy(String clientId);
}
Then carsOwnedBy method implementation retrieves a Client and returns only the Cars associated with it.
I have an entity in my domain which I need to track its status. And I have a handler for this need. This status is like InProgress, Completed or Deleted. And I use CosmosDb, SQL API for storing that data.
Inside CosmosDb, I have created a container for those created entities and another container for its status. Therefore, inside the code, I have two repositories for those two containers.
internal interface EntityRepository
{
Task AddAsync(Entity entity);
}
internal interface EntityStatusRepository
{
Task AddAsync(EntityStatus entityStatus);
}
And for each repository, I have created one service
public interface EnityService
{
Task AddAsync(Entity entity);
}
public interface EntityStatusService
{
Task AddStatusAsync(EntityStatus entityStatus)
}
Those services have been exposed as public interfaces for the handler and not repositories.
Now I really wonder
Based on DDD and having an entity and its status, should I create two separated repositories or they should be as one repository, as they are one context?
Do I need to expose the entity and its status through one service?
I wonder if anyone has a suggestion or even a better solution?
I'm not a DDD expert - just reading through Implementing DDD by Vernon but from my experience, you have an issue with bounded context. Your models Entity and EntityStatus are probably closely related. In that case you should create EntityStatusRepository only if you have a place where you need EntityStatuses by itself. If you need both of them just go with EntityRepository
It appears the EntityStatus should be a property on Entity, but let’s go through the logic to make sure. Note that these are not hard rules, just my rules of thumb when I’m going through these decisions. Extenuating circumstances my supersede these.
Should EntityStatus be an Aggregate Root? Would it make sense to
work with an EntityStatus by itself with no relationship to anything
else, or with only references to child objects? If not, then it is
not an Aggregate Root. That means it’s either a supporting entity or
a property.
If the parent entity always has exactly one current value of
EntityStatus, and no logic needs to be embedded inside the status,
then it is best to leave it as a property on the Entity.
If the EntityStatus needs logic built into it then it should probably
be a value object. For example, if status can only change from X to
Y in some circumstances but not others, or if some external process
must be launched when a status changes, it should be a value object
whose value is set by the Entity. Being a value object doesn't necessarily mean it's a separate entity, though.
Finally, I prefer to tie my repositories to Aggregate Roots even if there are value objects owned by the AR. An AR update should all be saved or nothing, and extending a DB single transaction across repositories is less than ideal. If you’re using the Unit of Work pattern, then an AR update should be a single unit. I’ve tried creating a separate repo per table where the AR repo uses the individual table repos, and it felt too granular with all the plumbing code. It was also easy to lose the business idea you’re trying to accomplish when dealing with all the pieces floating around. In the end, though, there’s no rule governing this so do what you think is right.
I'm trying to grasp more and more of Domain Driven Design and follow best practices. So far this is my understanding:
An aggregate is a collection of entities related to each other.
The root of the aggregate is the entity the binds the relationship of the aggregate together.
If the root is deleted everything within the confines of the aggregate must be deleted as well
Aggregate roots can only reference each other via identities
My questions are:
If I have more than one aggregate related to each other, say Orders And Product Categories.
How should the application service handle the retrieval of an order and related product category?
Should the service have a reference to each repository of an order and product category, retrieve the order first, then retrieve the product category, and finally fill out a data transfer object referencing the information from both?
Something like this:
public OrderDto GetOrder(int id)
{
var order = _orderRepo.GetById(id);
var productCategory = _categoryRepo.GetById(order.ProductCategoryId);
return new OrderDto
{
CustomerName = order.CustomerName,
ProductCategoryName = productCategory.Name,
*..etc..*
};
}
Or is it over kill to keep the roots that decoupled if they are tightly related?
Or should the UI be making the calls to independent services for the complete picture?
There are some situations you may have to break the rules according to Reasons to break the rules section
The first one of them is presetation convenience, it's not a big deal when you just neeed to display one Order at a time, but the solution you mentioned causes N + 1 query problem if you need to list Order s.
Alternative solution is stick to the rule and use your persistence object for rendering ui(in list Order case) if you want to seperate(or have already seperated) your domain models from persistence infrastructure, some discussion can be found here.
Using the CQRS pattern in your application seems an option. The pattern fits well with DDD because it helps us in this kind of situation where we need a different mechanism for writing and reading data, you can read more about CQRS in this article https://martinfowler.com/bliki/CQRS.html, so if you want to retrieve data for the purpose of display you don't need to get all the aggregate roots because invariance of the entity can't be invalid when reading data i.e the entity state is not changing.
What do you think? should your DAO return an IQueryable to use it in your controllers?
No. Your controllers shouldn't be handling any complex logic at all. Keep them slim; the Model (not DAO) should hand the Controller back everything it needs to pass onto the View.
Seeing queries (or even queryables) in a Controller class is something I would consider to be a code smell.
At the moment, it sounds attractive, but really isn't.
I love passing IQueryable into my controllers because I don't have to create lame paging and sorting methods in every single DAO method and interface throughout the lifetime of my apps development.
GetCustomersByLastname( string lastname )
Quickly Becomes
GetCustomersByLastname( string lastname, string sortcolumn, int pagesize, int page )
Again and again and again and again. Bleck!
With IQueryable you can take implement paging and sorting in orthogonal ways such as taking advantage of the IPagedList project. Returning IQueryable also give you easy access to total object .Count() without more perversion of your data layer.
#Robert s argument of IQueryable equals fat controllers is very shaky. A Fat controller would be similar to the bloated .aspx.cs pages of yore. If all your doing is connecting to your DAL and then shipping the results off your don't gain "fatness" from your query technique, you gain it from shoving lots of logic inside inside a single class. You do not get a Fat Controller because of your data access methods unless you start rolling logging, notifications, and other orthogonal concerns inside.
public ActionResult Detail( string searchTerm )
{
var model = MyDAL.MyObjects( searchTerm );
}
vs:
public ActionResult Detail( string searchTerm )
{
var model = MyDAL.MyObjects.Where( x => x.Name == searchTerm );
}
I don't see a compelling difference.
#Mark Seemann 's answer is equally shaky. Sure, you may change your entire data layer in the middle of a project but that is going to be a complex disaster no matter how abstracted you are. The example he uses is switching from Linq2Sql to Windows Azure's table storage. RDBMS to Key/Value store? And the pain point is your Repository implementation? Going from RDBMS to a Key/Value store is going to be some craziness thats going to be horrible no matter what.
Mark also brings up Domain Driven Design in his argument. Is that the type of system your building. Is there enough "Domain" rather than pure CRUD scenarios that make this approach valuable? If not then why bother?
Using and LINQ and the IQueryable interface gives you less of the pain of switching data layers anyway. If your switching between ORMs that support LINQ and IQueryableProvider ( I think thats the name ) than only the downstream code cares about that change. Your controllers would stay the same switching between from most ORMs on the market now.
If you follow the "fat models, skinny controllers" paradigm then no.
See this post on the Fat Controller anti-pattern.
Validation of Business Objects is a common issue, but there are some solutions to solve that.
One of these solutions is to use the standalone NHibernate.Validator framework, which is an attribute-based validation framework.
But I'm facing into conceptual concern. Attribute validators like NH.Validator are great but the validation is only performed when save-update-delete within the Session.
So I wonder if business objects should not be self-validated in order to maintain their own integrity and consistence?
IMHO - there are 2 steps of validations needed for a Business Object (BO)/Entity to be valid:
Step1: BO/Entity self-validation
- In this, we check only if the entity is valid in terms of its state F.Ex.: If postal code is set, then does it have valid characters & is of valid length etc. form the BO/Entity level validations. But beyond this level of validation, we would not be able to say that the BO/Entity is valid in your business domain and/or repository.
Typically the BO/Entity would be able to enforce this level of validation.
Step2: Context validation
- In this, we need to validate if the BO/Entity is valid within the context of the Repository where it is being persisted. F.Ex.: Is the postal code valid for the country in which the order is being placed/sent to etc.
For this validation, some or all entities in the current context might need to be involved to make sure the BO/Entity is valid.
So, to keep the entities pure, you will need to split the validation into these 2 steps - one performed by the entity itself & the second by the repository which is persiting/working with the entity.
HTH.
It's not always possible for them to self-validate though. What if you enter an "invalid" Zip Code? You could validate that the Zip Code needs to be in a specific format, but what if you want them to be "valid", that is "existing and matching the city"? Or what if you only accept phone numbers from certain area codes, and the list of valid codes is in a database maintained by the legal department?
If you can perform semantic validation, that's great and could go into the Business Class. But often, you might need extra validation that is simply not possible to handle by the business class itself but needs to be handled by the class that talks to the database and other external services.
I don´t know if we are talking about the same idea, but if we are, I like what you explain. Very quickly, I´ll explain what I do to solve this. In my case, all the bussines objects in my domain layer must override two methods:
Obviously, to maintain this, I have more classes implicated, but I´ll not write all here, cos I´m only trying to explain the concept
List<ValidationRule> notPassedValidationRules = new List<ValidationRule>();
//...
public override void ValidateErrorsWhenSaving(Validator validator)
{
//...
}
public override void ValidateErrorsWhenDelete(Validator validator)
{
//...
}
In these methods, I check for some boolean conditions, mantaining a collection of non passed rules. In my case, these methods are invoked before my Unit Of Work commits the changes (inserting new entities, updating, deleting), and show possible errors to the user, before commiting.