Domain Modeling with GORM
What Is GORM?
GORM (Grails Object Relational Mapping) is Grails' persistence layer, built on Hibernate but with a clean, expressive API. You describe your data model in Groovy domain classes and GORM handles tables, CRUD, relationships, validation, and transactions.
A Domain Class
class User {
String username
String email
Date dateCreated
}By convention, the class name maps to the table name, properties map to columns, and id plus version fields are added automatically. The optional dateCreated and lastUpdated fields are filled by Grails when enabled.
Table Creation
dataSource:
dbCreate: updateThe dbCreate options are create, create-drop, update, validate, and none. Use update in development only - in production use none, with migrations like Flyway or Liquibase managing schema changes.
Constraints and Validation
class User {
String username
String email
static constraints = {
username blank: false, unique: true
email email: true
}
}Common constraints include blank, nullable, unique, size, max, min, and email. Validation runs automatically whenever you call save().
Essential GORM Operations
def user = new User(username: "admin", email: "admin@test.com")
user.save()
def all = User.list()
def one = User.get(1)
User.findByUsername("admin")Updating and Deleting
def user = User.get(1)
user.email = "new@test.com"
user.save() // dirty checking tracks the change
def victim = User.get(2)
victim.delete() // wrap in a transaction in productionLifecycle Events
class User {
def beforeInsert() { log.debug "...about to insert" }
def beforeUpdate() { log.debug "...about to update" }
}Useful for auditing and logging without cluttering actions.
Custom Mappings
static mapping = {
table 'app_user'
email index: true
cache true
}You control table names, column names, indexes, and caching from one block.
Transient Fields
Fields you do not want persisted are declared transient:
static transients = ['fullName']
String getFullName() { "$firstName $lastName" }Common GORM Mistakes
- Ignoring validation errors from save().
- Saving outside transactions in production.
- Overusing domain inheritance.
- Writing business logic in domain classes.
Key Points
- Domain classes define tables and validation.
- save/list/get/findBy cover most data work.
- Constraints validate automatically on save.
- Lifecycle hooks help with auditing.
- Keep domains simple; put logic in services.
