GORM mappings
GORM features
GORM advantages (a lot less code):
- constraints - powerful free validation
- dynamic query - tons of free methods - e.g. findOrCreateById(id)
- auto cascade deletion - belongsTo
- easy transaction and rollback
GORM disadvantages (sometimes not flexible):
- shared logic - hard to share a method that uses Grails dynamic query
- inheritance doesn't work well - all the children would become one big shared table with null value columns
GORM tricky but good features:
fetch and modify
- Feature: GORM would save the modification automatically
- Why tricky: unexpected behaviours
- Why good: modification in the fetching process is BAD BAD practice, so it forces people to avoid it
transaction
- Feature: Grails / Hibernate doesn't allow fetching the same object in one transaction
- Why tricky: you may need the DB copy again sometimes - e.g. find and filter in Grails
- solution: discard() the items being filtered
Relationships
- hasOne / hasMany - avoid using (reasons):
- have to provide matching hasOne or hasMany
- not recommended to be used due to performance
- foreign key automatic conversion - can be achieved if using simple types - e.g. int, string, date, boolean
- they require maintaining the FK on both sides of the domains - e.g. changing a parent needs to be done in 2 places
- belongsTo - encouraged
- it provides automatic cascading deletion
- use them when requiring parent to cascade delete (makes no sense for children to exist if parent is deleted)
Server to client data (auto-conversion)
| types to be sent to client side | include in client data | reason |
|---|---|---|
| primitive types | yes | |
| date | yes | |
| custom objects - e.g. address | no | flat data allows auto conversion |
| collections - e.g. chart.hierarchyIds | no | only maintained on server side, to avoid changing 2 places when changing fk (maintaining the list and a fk in client side) |
Domain data relationship (when data is referenced)
- cascade deletion
- prevent deleting
Strategy to handle DB legacy data

Key points to achieve this (example: inconsistent chartPosition in MisChartColumns - some starts from 0, some starts from 1):
- hierarchyPosition - field to be used for client side only - don't map it to DB (set to transients, so that no Hibernate ignores it)
- chartPosition - don't have chartPosition field on MisChartColumn class (set to client side excluded)
- but provide get set java bean methods for e.g. chartPosition
- they run some logic, then set appropriate value to hierarchyPosition
- get method - used by Hibernate to persist a value to DB
- set method - used by Hibernate to indirectly set value to hierarchyPosition
- conversion
- set methods - hibernate follow the generated sql order to set properties
- to guarantee no dependencies when setting values - run SQL to get DB values if needed
- benefit of using SQL in conversions:
- no dependency
- no hibernate session involved
- good practice: only using query SQL to check things - e.g. checking if D2 exists when resolving D1
- bad practice: run update statements as side effect (results in unpredicted change)