Domain Driven Design – Converting Database Table with Primary Key into Value Object

domain-driven-designdomain-modelvalue-object

Lets suppose there's a database schema defined like this:

Person.mail_address_key ----- Address.address_key
Person.billing_address_key ----- Address.address_key

A Person has a mailing address and a billing address. As a denormalization technique, we create a separate Address table. Most of the time the mail_address_key and the billing_address_key of a single Person will be the same value (ie: their mailing and billing address key will be the same).

In my database the Address has an identity (the address key). But, in my domain model, I don't see a compelling reason for the Address to be an Entity, I'd like it to be a Value Object.

  1. In DDD, is this an option? Or are Value Objects usually a group of columns (as opposed to a table)? I'm kind of playing the devil's advocate here, because I don't think the database should dictate the domain model structure, but just making sure.
  2. If so, where/when/how does the address lose its database identity so it can be used as a Value Object in the Domain Layer? Or, am I supposed to keep the database identifier in the Value Object?
  3. When the model needs to be persisted in the database, what's the process? Am I supposed to go through a process of a) Find an address by these fields, b) if it doesn't exist, create a new one c) if it does, update the fields?

Best Answer

In DDD, is this an option? Or are Value Objects usually a group of columns (as opposed to a table)? I'm kind of playing the devil's advocate here, because I don't think the database should dictate the domain model structure, but just making sure.

The database should not dictate the domain model structure so you're correct on that. Value objects can be stored in the database as either a column or table depending on the type of data the value object is supposed to carry.

If so, where/when/how does the address lose its database identity so it can be used as a Value Object in the Domain Layer? Or, am I supposed to keep the database identifier in the Value Object?

Your domain code should not be riddled with properties that are for other concerns like persistence since they should be completely persistence ignorant. You should really focus on your aggregate root. You must have some way of identifying your aggregate root when you save it back to the database so, at that point, you would just need to check the Person table record (I'm assuming Person is your aggregate root) and see if there is a value in the MailingAddressID or BillingAddressID field. At that point, you can decide whether to create new addresses and change the links to point to the new addresses or overwrite the addresses that are already linked.

When the model needs to be persisted in the database, what's the process? Am I supposed to go through a process of a) Find an address by these fields, b) if it doesn't exist, create a new one c) if it does, update the fields?

As I somewhat explained in the above answer, you should hydrate and de-hydrate your object graph based on your aggregate root. Therefore, when your repository gets your aggregate root from the database, it will also hydrate all of the necessary entities and value objects under your aggregate root that are associated with your aggregate root in the database. The same is true when you go to save the aggregate root back to the database. Your repository should be able to handle your entire object graph under the aggregate root.