I have done an IMMENSE amount of reading about domain driven design and have done some fairly complex projects with that design. All of them had their flaws and anti-patterns that were realized along the way. Understandable as this was a learning process. I, however, am stuck on a major concept that I cannot seem to resolve via Google (maybe I'm just not coming up with the right search terms) or by my own trial and error.
I have read several articles that claim emphatically to keep your Domain Model and your Persistence Model separate. Don't let things like an ID leak into your Domain Model unless there is a domain purpose for that ID. With that policy, how does one persist a Domain Model IN PRACTICE? All the articles I have read talk about this in the abstract, but I cannot find a concrete example that DOESN'T violate this.
I have a relatively large and complex web application that I'm building and would like to achieve the "best" Domain and Persistence separation I can. I am using a hand-rolled ORM (yes, yes, I know - I shouldn't - blah blah blah - however, the underlying tables and queries are much too complex to use something like EF or NHibernate well). In this accounting package at a large university, I have General Ledger Journal Entries with the following structure:
Public Class Journal
Public Property AccountCode As SFSAccountCode = Nothing
Public Property Amount As Decimal = 0
Public Property BudgetCategory As BudgetCategory = Nothing
Public Property [Date] As DateTime = Nothing
Public Property ChildAccount As ChildAccount = Nothing
Public Property Description As String = ""
Public Property FiscalYear As SFSFiscalYear = Nothing
Public Property Fund As Fund = Nothing
Public Property JournalID As Int32 = -1
Public Property Notes As String = ""
Public Property Program As String = ""
Public Property Source As JournalSource = Nothing
Public Property Status As JournalEntryStatus = JournalEntryStatus.Open
Public Property TransactionType As TransactionType = Nothing
End Class
Without including the uniqueID (JournalID), how can I map an instance in the Domain Model to an instance in the Persistence Model? From my understanding, you are to consider an object unique by its invariants. Easy, if your object is only one or two properties as strings or ints. I clearly have many properties of which several are domain models themselves.
I'm sure there is some key concept that I have just missed - can anyone point me to a resource (with concrete code as bonus!) to help explain how one can map between a persistent model with database IDs to a domain model without?
By the way, yes I know my properties should be private sets for good domain design. And they will be once I can figure out the mappings between persistence and domain better. And I happen to code in VB.NET but can read Java or C# fine, as I'm sure most examples will be in one of those two languages.
A domain model should always be concerned with domain BEHAVIOR, while a persistence model, at most, it stores domain object STATE. The persistence models what you want to store from an object and that data will be used to restore the object.
A persistence model assumes that the future value of a time series is calculated under the assumption that nothing changes between the current time and the forecast time.
In software engineering, a domain model is a conceptual model of the domain that incorporates both behavior and data. In ontology engineering, a domain model is a formal representation of a knowledge domain with concepts, roles, datatypes, individuals, and rules, typically grounded in a description logic.
The Domain Model should represent the vocabulary and key concepts of the problem domain and it should identify the relationships among all of the entities within the scope of the domain. The Domain Model itself could be a diagram, code examples or even written documentation of the problem.
According to Domain Driven Design:
There are entitiy objects (entities) and value objects (values). Values are identified by a set of values (or fields). Thus, if we have two value objects with same fields, they are not disinguishable for us (as model in real life). Often value objects are immutable.
Entity objects are not identified by contained values. Entity objects are identified by its own unique existance. We cannot say that two persons with same name presents single real man.
For example:
class ProductAmountPair {
public Product Product { get; set; }
public int Amount { get; set; }
}
class Order {
public int Id;
public IList<ProductAmount> { get; set; }
}
ProductAmount is a value, and Order is an entity (actually it depends on concrete case).
To identify entity object, it is necessary to determine some unique value (key). In some domains keys are given externally (from real life), but another ones requires to generate it and thus application itself defines a way to do that.
So, conclusion is: for entities we have to introduce key field to identify them. It is necessary since entities cannot be identified by a set of values they contain.
Ok, what about database and its role.
Today databases are not just only data storage, but are complicated mechanism for ensuring of the data integrity, transactins processing, etc. Very often complex tasks like concurrent access are solved by applications just by "broadcasting" them to database.
By the same reasons databases are often used to generate key values, they propose good reliable mechanism to obtain new unique values. So, keys are generated by database because it is easy to implement, and keys are used to map domain model entities to persistance model because it is natural.
One can say, that DB engines requires to create primary keys for each table, and thus every class in domain should have key field, and thus it is entity. But:
Why should we consider databases (even relational databases!) when talking about domains? In his DDD book Eric Evans says "do not confront with technologies and paradigms".
Sometimes, because of strong performance or realiablity requirements we have to give up some DDD purity and clearness and make domain model more (for example) "relational" (I mean class-table mappings mostly).
We just have to deal with it.
For same reasons we can admit a partially "techincal" role of key field of entity. But also we admit its main role as domain identification attribute.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With