In my domain I have an Account
object.
e.g.
class Account
{
public string Number;
public string SortCode;
}
Within the context of DDD, should this account object have an ID
property? The ID
would be a primary key, basically a database artefact.
8
It depends. If your Account
class shall be mapped to a relational database, then its not just a good idea, but proven practice, to use technical IDs for every table as PKs (and FKs, referencing those PKs). To my experience, separating the technical PK of all tables from the “domain keys” (like the “bank account number”) works very well and helps you to avoid all kind of technical issues. I typically name those PKs not just ID
, but <class-Name>Id
, so in your case AccountID
.
If your class above will just be used as an input to a code generator which will generate the “real” code of your implementation language as well as your CREATE TABLE
statements, some CRUD code etc., you probably don’t need to add the ID attribute in the class code directly. If you are going to use an ORM, it depends on the ORM if it can add ID attributes as PKs automatically, or if it expects you to add those IDs manually.
In a DDD context, it may probably be helpful to hide those technical details when discussing the model with your domain experts, but show them when you change your viewpoint to the implementation of the model. If your tool set allows to display the model in those different levels of abstraction, make use of it. But if the tool set does not allow it, add the ID attributes and tell your domain experts that those are just “technical attributes”.
9
Most of the time, the ID
field you are talking about would be generated by the database, e.g. as a RDBMS sequence or a NoSQL unique identifier. It is therefore tied to the corresponding database backend used.
According to the Persistence Ignorance / Polyglot Persistence principle, you should better hide this ID
from your domain aggregates as much as possible.
In practice, your domain Aggregates may already have an unique identifier. For instance, a serial number, a client code, a logon name, an account number, an invoice reference or an ISBN for a book.
If there is no such “natural” identifier in your model, it may be one role of the domain logic to generate such genuine identifiers, e.g. following a pattern defined by regulation, or human-friendly notions, following your company best practice (it is common to include the year and the month in invoice numbers, or an alphanumeric identifier of the department in charge of the process for instance).
Within the Infrastructure Layer, you would probably let an ID
field appear, especially if you need to construct joined SQL queries among several RBDMS tables. Or, if you use an ORM, you may not persist directly the DDD aggregate objects as ORM objects, but use an “agnostic” translation layer. This is for instance what our DDD framework proposes, by adding an automated translation layer between the DDD plain objects and the ORM objects, which have their own ID… some kind of “square ORM”: on DDD mapper over an ORM mapper.
DDD is mainly about isolation: don’t pollute your domain with database consideration! Naming an aggregate object field as ID
does definitively smell: there is probably another naming, compatible with the Ubiquitous Language of your bounded context, which may be used instead of a plain ID
.
1
I don’t think that id is a database artefact. How do you know that account you are working with is correct? You know it’s a correct account because it probably has a unique identifier. In your case the unique identifier is called “Id”, so naturally you think it’s a database artefact. Because of this I think that it’s perfectly fine to have Id property in your domain model.
On a side note, I would NOT have a foreign key property in a domain model. For example, instead of having AddressId in the domain model, I would have an Address property and that would contain the address id.
5
The question easer to answer from the end. You are trying to add primary key, since I would use following thought process
- Why we need PK? – are we going to search in this table? Is it more than 3-10 records etc? – If we can say yes, that means we have a need for clustered index (do not mix with PK, PK creates it as a side effect).
A clustered index is an index which defines the physical order in which table records are stored in a database.
-
Do we really need PK or it is enough to have unique key? – Unique also can be the baseline for clustered index. Let’s imagine we can use unique
-
How big index key would be? – There might be multiple options but let’s consider only 2: Your field Number is unique and can be from 1 to 50000. The uniqueness of record can be define only by combination of fields SortOrder and Number. While in 1st option I would most likely create PK on top of field Number, in second one I would introduce generic ID to simplify clustered index structure and size.
Now we can get back to DDD itself – “In terms of object-oriented programming it means that the structure and language of software code (class names, class methods, class variables) should match the business domain. For example, if a software processes loan applications, it might have classes like LoanApplication and Customer, and methods such as AcceptOffer and Withdraw.”
ID logically is a result of function executed against the attributes that uniquely identify your record and produce integer as output, since it is a synthetic attribute of your domain model. It may be required to shorten object identification or not.
However worth to mention that applying different structure to different tables confuse developers (and that is major reason, why people use ID), practically you truly needed rarely. So it is also about balance in code and ability to maintain it.