1. On Parent Side
Since we always mark insertable=true and updatable=true in @JoinTable of parent side by default, we only discuss the child side:
2. On Child Side
2.1. With Join Table (Using @JoinTable)
2.1.1. The Children
2.1.2. What does insertable = updatable = false mean?
Note that we have made both JoinColumn's to have attributes:
insertable = falseupdatable = false
which makes the child side completely ready-only.
For @JoinTable the dirty check for the assignement
insertable = falsewill not insert a relation into the join tableupdatable = falsewill not update the relation in the join table
Now the relation is completely controlled by the parent, which is usually an aggregate, via as simply as
2.2. Without Join Table (Using @JoinColumn)
Which means that a table has a column that directly points to the primary key of another column. For example:
2.2.1. The Children
2.2.2. What does insertable = updatable = false mean?
For @JoinColumn now the dirty check for the assignment
insertable = falsewill not includeshell_script_idin theINSERTstatement of persistingaiScriptedToolupdatable = falsewill not updateshell_script_idin theUPDATEstatement of modifyingaiScriptedTool
But then how to set the relation properly? We strictly follow the following steps:
- Persist the parent and get
parentId. - Persist the children and assign that
parentId.
3. When do we want insertable=true and updatable=true?
insertable=true and updatable=true?3.1. Enforce Domain Logic by Making Constructor Private
3.1.1. Scenario
It is not rare and one common scenario is:
You want to private out the constructor of an aggregate and create factory method for your entity objects to enforce domain logics.
For example, a Message entity must be one of TextMessage, ImageMessage and VoiceMessage, therefore creating and persisting the Message object alone in the database will violate the domain logic.
In other words, Message and one of the remaining classes must appear in pair.
3.1.2. Code Example (Factory Pattern)
By privating the constructor we can write
This is known as Factory Pattern and widely used in Domain Driven Design.
Now no one can create Message entity alone, prohibiting invalid domain logic from the prospective of data integrity in coding level.
3.2. Caveat for Different Choices of Databases
3.2.1. Failure in SQLite
The save behaviour for the above bidirectionally-bound entities can vary in different databases.
Takes these lines for example:
-
The above throws an exception for SQLite because SQLite enforces foreign key constraints immediately during each
INSERT, which- Tries to persist
audioMessagefirst (without our control); However - No available
idcan be assigned toAudioMessage.messageIdat that time.
- Tries to persist
-
Other databases (such as PostgreSQL, MySQL) can defer Foreign-Key checks until transaction commit, unforturnately SQLite does not.
-
JPA does not change its persistence strategy (order of persistence) based on different dialects.
3.2.2. For Database that Supports Deferred Constraint Checking
If our choice of database supports the above operations, just go ahead. Otherwise the persist parent first, then persist child rule is the most reliable.












