Edition 0 Updated to asp. Net core 0


Encapsulate data in the Domain Entities



Yüklə 11,82 Mb.
Pdf görüntüsü
səhifə182/288
tarix12.07.2023
ölçüsü11,82 Mb.
#136458
1   ...   178   179   180   181   182   183   184   185   ...   288
Encapsulate data in the Domain Entities 
A common problem in entity models is that they expose collection navigation properties as publicly 
accessible list types. This allows any collaborator developer to manipulate the contents of these 
collection types, which may bypass important business rules related to the collection, possibly leaving 
the object in an invalid state. The solution to this is to expose read-only access to related collections 
and explicitly provide methods that define ways in which clients can manipulate them. 
In the previous code, note that many attributes are read-only or private and are only updatable by the 
class methods, so any update considers business domain invariants and logic specified within the class 
methods. 


208 
CHAPTER 6 | Tackle Business Complexity in a Microservice with DDD and CQRS Patterns 
For example, following DDD patterns, 
you should 
not
 do the following
from any command handler 
method or application layer class (actually, it should be impossible for you to do so): 
// WRONG ACCORDING TO DDD PATTERNS 

CODE AT THE APPLICATION LAYER OR
// COMMAND HANDLERS
// Code in command handler methods or Web API controllers
//... (WRONG) Some code with business logic out of the domain classes ...
OrderItem myNewOrderItem = 
new
OrderItem
(orderId, productId, productName, 
pictureUrl, unitPrice, discount, units); 
//... (WRONG) Accessing the OrderItems collection directly from the application layer // or 
command handlers
myOrder.
OrderItems
.
Add
(myNewOrderItem); 
//...
In this case, the Add method is purely an operation to add data, with direct access to the OrderItems 
collection. Therefore, most of the domain logic, rules, or validations related to that operation with the 
child entities will be spread across the application layer (command handlers and Web API controllers). 
If you go around the aggregate root, the aggregate root cannot guarantee its invariants, its validity, or 
its consistency. Eventually you will have spaghetti code or transactional script code. 
To follow DDD patterns, entities must not have public setters in any entity property. Changes in an 
entity should be driven by explicit methods with explicit ubiquitous language about the change they 
are performing in the entity. 
Furthermore, collections within the entity (like the order items) should be read-only properties (the 
AsReadOnly method explained later). You should be able to update it only from within the aggregate 
root class methods or the child entity methods. 
As you can see in the code for the Order aggregate root, all setters should be private or at least read-
only externally, so that any operation against the entity’s data or its child entities has to be performed
through methods in the entity class. This maintains consistency in a controlled and object-oriented 
way instead of implementing transactional script code. 
The following code snippet shows the proper way to code the task of adding an OrderItem object to 
the Order aggregate. 
// RIGHT ACCORDING TO DDD--CODE AT THE APPLICATION LAYER OR COMMAND HANDLERS
// The code in command handlers or WebAPI controllers, related only to application stuff
// There is NO code here related to OrderItem object's business logic
myOrder.
AddOrderItem
(productId, productName, pictureUrl, unitPrice, discount, units); 
// The code related to OrderItem params validations or domain rules should
// be WITHIN the AddOrderItem method.
//...
In this snippet, most of the validations or logic related to the creation of an OrderItem object will be 
under the control of the Order aggregate root

in the AddOrderItem method

especially validations 
and logic related to other elements in the aggregate. For instance, you might get the same product 
item as the result of multiple calls to AddOrderItem. In that method, you could examine the product 
items and consolidate the same product items into a single OrderItem object with several units. 


209 
CHAPTER 6 | Tackle Business Complexity in a Microservice with DDD and CQRS Patterns 
Additionally, if there are different discount amounts but the product ID is the same, you would likely 
apply the higher discount. This principle applies to any other domain logic for the OrderItem object. 
In addition, the new OrderItem(params) operation will also be controlled and performed by the 
AddOrderItem method from the Order aggregate root. Therefore, most of the logic or validations 
related to that operation (especially anything that impacts the consistency between other child 
entities) will be in a single place within the aggregate root. That is the ultimate purpose of the 
aggregate root pattern. 
When you use Entity Framework Core 1.1 or later, a DDD entity can be better expressed because it 
allows 
mapping to fields
 in addition to properties. This is useful when protecting collections of child 
entities or value objects. With this enhancement, you can use simple private fields instead of 
properties and you can implement any update to the field collection in public methods and provide 
read-only access through the AsReadOnly method. 
In DDD, you want to update the entity only through methods in the entity (or the constructor) in order 
to control any invariant and the consistency of the data, so properties are defined only with a get 
accessor. The properties are backed by private fields. Private members can only be accessed from 
within the class. However, there is one exception: EF Core needs to set these fields as well (so it can 
return the object with the proper values). 

Yüklə 11,82 Mb.

Dostları ilə paylaş:
1   ...   178   179   180   181   182   183   184   185   ...   288




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©azkurs.org 2024
rəhbərliyinə müraciət

gir | qeydiyyatdan keç
    Ana səhifə


yükləyin