In DDD, in an aggregate root of Person with a Value Object of Address, mapping that address to a database table is simple: just embed the attributes of the Address object into the record. But what about when the Person has a List, where the count can vary? Do we create a separate table that stores all our Addresses (thereby imposing some quasi-identity on each one), and each row with an FK back to the Person to which it belongs?
There is a good example of object-relational impedance mismatch. What you can do is have a layer super-type where persistence concerns such as an id field lives. Therefore, from your persistence layer's point of view, the VO is an entity, but still modeled as a VO in the domain.
You can read more about the above here.
Related
Say I have a "Directory" bounded context with 2 aggregate roots. Company and Person. Company has a collection of child entities "Position" that hold the IDs of a person aggregate with some extra value data.
All good.
Now we go and add a "Article" bounded context with an aggregate root JobAriticle. This needs a Contact value object which is mapped from a company position.
So knowing that you should only reference aggregate roots what should I do? Assume there are invariants on the Company to Position relationship so I don't want to split the aggregate. Is it OK to map a Position through the anti corruption layer with both the company and position ids? Or do I need to try and break apart the company aggregate.
If Position is a meaningful concept in the Ubiquitious Language of the "Article" bounded context then Position should be either a ValueObject or Entity in the "Article" bounded context.
If you're saying that Contact is the meaningful concept in the "Article" bounded context, but that it needs to somehow correlate with a Position in the "Directory" bounded context, then you need to think about what is the purpose of that correlation:
Do you need to verify that a position exists before creating a contact on a JobArticle?
Is there some shared data that will be kept in sync between a Position and a Contact?
What happens if a Position is archived/deleted or otherwise rendered out of service - do you have to do something to all the contacts?
If you need to verify that a Position exists before creating an associated Contact, then implicitly Position plays a role in the responsibilities of the Article context - so I would be tempted to create a new Position entity in the Article context and keep it in sync.
Either way, to correlate something in the Article context with a corresponding entity in the Directory context, you could create a ValueObject in the "Article" context called PositionCorrelation which would have two properties:
CompanyId (globally unique)
PositionId (locally unique within a company)
The rule that aggregates should only reference other aggregate roots doesn't mean that you can't also provide information with which to identify entities within the aggregate. It just means that if you want to interract with the other entity, you should do it via the aggregate root, which means you must at least have the aggregate root Id. If you then use a local Id to ask the Company to do something to one of it's positions, that's fine.
But - be aware, that by following this approach, you are introducing the term "Position" into the "Article" bounded context, which may introduce a name collision if the word "Position" means something else in the "Article" context - e.g. perhaps it means the position within an article (paragraph number etc.). If this is the case, you need to think carefully about what to call the cross-context identifier.
One approach could be that if Position has a one to one map with Contact, then you could have your two properties be:
CompanyId
CompanyContactId
And when keeping in sync at the Anti-Corruption layer (ACL) when integrating between the contexts, define CompanyContactId and PositionId (local within Company) values as being synonomous. This keeps each UL internally consistent and defines the correlation between the two in an ACL.
Lots of examples like order and order lines makes sense, like:
Order is an AR that contains OrderLines
Customer is an AR that contains Orders.
Question is, what is the AR that contains Customer?
I guess it can be something like "shop".
So, shop.AddCustomer(customer)...
but, how to get shop?
If it's an AR (entity) it has an id, so shop.GetById(shopId). If I only have one shop, how does this work with persistence?
Should I have a table (shops) with one line?
Shop is an in-memory object with a collection of Customers?
You got that wrong there. Aggregates do not contain other aggregates! They can only reference them by ID.
An aggregate is a group of entities and value objects that are closely related. The aggregate forms a consistency boundary around them. The Aggregate Root is the root entity in that aggregate that is globally addressable. So in your example with Order and OrderLines, Order could indeed be the AR.
Customer on the other hand, would only reference Orders by ID if it is a separate aggregate.
To retrieve an aggregate, you typically use a Repository. You load an aggregate through the repository by specifying the ID of the aggregate, or some other suitable search parameter.
Question about using Aggregates (not AR) in Domain Driven Design.
Using the familiar: Order (aggregate root [AR]) and OrderLine (aggregate member [AM]) works for an example. If one assumes that the Orders are persisted, then how does one, properly from a DDD perspective, operate on the aggregate members?
For instance, can I search (find operation) for all the OrderLines of a given item? What is the correct way to do that? If I return those as Value Objects, that just seems wrong, in reality they are persisted Domain Objects. Furthermore, I might need to be able to get the Order from one of them. Yet, if I return them (from the Repository layer) as Entity objects, then I seem to have violated the Aggregate Root canonical rule.
I think I have the answer to my question. If I now follow correctly, it's completely okay to know about an entity below the aggregate root. However, one can not store/view/reference an ID to it. But you CAN reference the AR Id.
Thus, I can have say: OrderRepository.findOrderLines(withProductId) method that returns a list of OrderLine objects less their Id, but having the Order Id (AR ID) on those objects is fine.
Please comment if this is off-base.
I am working on an application where users can follow each other, in a similar fashion to Twitter.
After reading up on DDD, I understand that my users are Entity Objects - I refer to them using their unique ID.
When one user 'follows' another (i.e. forms a Connection), the relationship is stored in a many-to-many table. Its fields include FollowerID, TargetID, and Status. There can be only two records for each Follower/Target combination (one Active, the other Inactive), so I can safely identify objects based on their attributes.
So, I think my Connection objects are Value Objects, not Entity Objects, but I'm not sure. Can you help me with this decision?
You are correct that entities are unique and carry the notion of having an identity (i.e. only one unique user can exist). A Connection is dependent on other User entities. It represents some aspect between two users. That aspect is whether there is an active or inactive connection. Without containing the data of which users are connecting, a connection has no identity. It may even have it's own primary key in the database, but from a domain perspective, it has no identity of it's own.
Therefore, I would say that Connection is a value object.
To support my conclusion, Microsoft.Net Architecting Applications for the Enterprise, page 187, says:
A value object class represents an entity in the domain that mostly
contains data and lives for the data it contains. A value object is
fully identified by a combination of values it contains. An entity
object, on the other hand, has its own life and rich behavior
regardless of the data it contains. Entity objects are usually objects
with a longer lifetime. A value object represents an aspect of an
entity and can live only in relation to an entity.
And also on page 189:
One further comment is needed to explain the difference between
entities and value objects. You don’t need a repository or a data
mapper for a value object. You need a repository only for an entity.
The repository (or the mapper) for a given entity will certainly take
care of all value objects that depend on a given entity.
Some time ago, I saw a cartoon about scientist that had invented cloning. Every time he cloned himself, he destroyed previous version. Then person that was watching demonstration decided to interrupt and sabotaged destruction part so there were two scientists. Cartoon ended with some interesting existential questioning.
Values vs entities is not about having or not having id fields in one or another form. Point is - how we are looking at those objects through our domain perspective. If they are value objects, then only their value matters - 1st, 3rd and 53rd scientist are the same. If we care about identity, if we think that cloning 3rd scientist will never be like 1st one, then our object is an entity.
I have a domain model
Customer - Aggregate root - because an order can't exist without a customer
Order - entity
OrderStatus - value object
In my form I need a list of all OrderStatuses.
Should I fetch an empty customer entity(AR) from repository with an empty order entity which is containing a list of all OrderStatuses? This is awkward.
Well, it always depends on your problem domain, but lacking further info, I would say you probably need to break your modeling a little bit.
Even though an Order can't exist without a Customer, it will not be a child entity under the Customer AR. You need to introduce the notion of Bounded Contexts.
Customer would be the AR of one BC, while Order would be the AR of its own BC.
In that case, you would reference Customer from Order with a CustomerId property (not with an object reference) because they belong to different contexts, and as such they could even live in separate microservices, in separate databases.
You see where I'm going: it makes no sense to fetch an empty Customer, with an empty Order (or list of Orders) just to reach a list of Order Statuses.
Even if Order and Customer did belong to the same BC, OrderStatus is Reference Data, and would be better represented by an enum type (or better, with the Enumeration Pattern).
Have a look at this additional info:
Reference data as code
Entities, Value Objects, Aggregates and Roots