## 5.5.1 Events and Auto Timestamping

GORM supports the registration of events as methods that get fired when certain events occurs such as deletes, inserts and updates. The following is a list of supported events:

- `beforeInsert` - Executed before an object is initially persisted to the database
- `beforeUpdate` - Executed before an object is updated
- `beforeDelete` - Executed before an object is deleted
- `beforeValidate` - Executed before an object is validated
- `afterInsert` - Executed after an object is persisted to the database
- `afterUpdate` - Executed after an object has been updated
- `afterDelete` - Executed after an object has been deleted
- `onLoad` - Executed when an object is loaded from the database

To add an event simply register the relevant closure with your domain class.

> Do not attempt to flush the session within an event (such as with obj.save(flush:true)). Since events are fired during flushing this will cause a StackOverflowError.

### Event types

#### The beforeInsert event

Fired before an object is saved to the db

    class Person {
       Date dateCreated   def beforeInsert() {
           dateCreated = new Date()
       }
    }

#### The beforeUpdate event

Fired before an existing object is updated

    class Person {
       Date dateCreated
       Date lastUpdated   def beforeInsert() {
           dateCreated = new Date()
       }
       def beforeUpdate() {
           lastUpdated = new Date()
       }
    }

#### The beforeDelete event

Fired before an object is deleted.

    class Person {
       String name
       Date dateCreated
       Date lastUpdated   def beforeDelete() {
          ActivityTrace.withNewSession {
             new ActivityTrace(eventName:"Person Deleted",data:name).save()
          }
       }
    }

Notice the usage of `withNewSession` method above. Since events are triggered whilst Hibernate is flushing using persistence methods like `save()` and `delete()` won't result in objects being saved unless you run your operations with a new `Session`.

Fortunately the `withNewSession` method allows you to share the same transactional JDBC connection even though you're using a different underlying `Session`.

#### The beforeValidate event

Fired before an object is validated.

    class Person {
       String name   static constraints = {
           name size: 5..45
       }   def beforeValidate() {
           name = name?.trim()
       }
    }

The `beforeValidate` method is run before any validators are run.

GORM supports an overloaded version of `beforeValidate` which accepts a `List` parameter which may include the names of the properties which are about to be validated. This version of `beforeValidate` will be called when the `validate` method has been invoked and passed a `List` of property names as an argument.

    class Person {
       String name
       String town
       Integer age   static constraints = {
           name size: 5..45
           age range: 4..99
       }   def beforeValidate(List propertiesBeingValidated) {
          // do pre validation work based on propertiesBeingValidated
       }
    }def p = new Person(name: 'Jacob Brown', age: 10)
    p.validate(['age', 'name'])

> Note that when `validate` is triggered indirectly because of a call to the `save` method that the `validate` method is being invoked with no arguments, not a `List` that includes all of the property names.

Either or both versions of `beforeValidate` may be defined in a domain class. GORM will prefer the `List` version if a `List` is passed to `validate` but will fall back on the no-arg version if the `List` version does not exist. Likewise, GORM will prefer the no-arg version if no arguments are passed to `validate` but will fall back on the `List` version if the no-arg version does not exist. In that case, null is passed to `beforeValidate`.

#### The onLoad/beforeLoad event

Fired immediately before an object is loaded from the db:

    class Person {
       String name
       Date dateCreated
       Date lastUpdated   def onLoad() {
          log.debug "Loading ${id}"
       }
    }

`beforeLoad()` is effectively a synonym for `onLoad()`, so only declare one or the other.

#### The afterLoad event

Fired immediately after an object is loaded from the db:

    class Person {
       String name
       Date dateCreated
       Date lastUpdated   def afterLoad() {
          name = "I'm loaded"
       }
    }

#### Custom Event Listeners

You can also register event handler classes in an application's `grails-app/conf/spring/resources.groovy` or in the `doWithSpring` closure in a plugin descriptor by registering a Spring bean named `hibernateEventListeners`. This bean has one property, `listenerMap` which specifies the listeners to register for various Hibernate events.

The values of the map are instances of classes that implement one or more Hibernate listener interfaces. You can use one class that implements all of the required interfaces, or one concrete class per interface, or any combination. The valid map keys and corresponding interfaces are listed here:

Name | Interface
--- | ---
auto-flush | AutoFlushEventListener
merge | MergeEventListener
create | PersistEventListener
create-onflush | PersistEventListener
delete | DeleteEventListener
dirty-check | DirtyCheckEventListener
evict | EvictEventListener
flush | FlushEventListener
flush-entity | FlushEntityEventListener
load | LoadEventListener
load-collection | InitializeCollectionEventListener
lock | LockEventListener
refresh | RefreshEventListener
replicate | ReplicateEventListener
save-update | SaveOrUpdateEventListener
save | SaveOrUpdateEventListener
update | SaveOrUpdateEventListener
pre-load | PreLoadEventListener
pre-update | PreUpdateEventListener
pre-delete | PreDeleteEventListener
pre-insert | PreInsertEventListener
pre-collection-recreate | PreCollectionRecreateEventListener
pre-collection-remove | PreCollectionRemoveEventListener
pre-collection-update | PreCollectionUpdateEventListener
post-load | PostLoadEventListener
post-update | PostUpdateEventListener
post-delete | PostDeleteEventListener
post-insert | PostInsertEventListener
post-commit-update | PostUpdateEventListener
post-commit-delete | PostDeleteEventListener
post-commit-insert | PostInsertEventListener
post-collection-recreate | PostCollectionRecreateEventListener
post-collection-remove | PostCollectionRemoveEventListener
post-collection-update | PostCollectionUpdateEventListener

For example, you could register a class `AuditEventListener` which implements `PostInsertEventListener`, `PostUpdateEventListener`, and `PostDeleteEventListener` using the following in an application:

    beans = {   auditListener(AuditEventListener)   hibernateEventListeners(HibernateEventListeners) {
          listenerMap = ['post-insert':auditListener,
                         'post-update':auditListener,
                         'post-delete':auditListener]
       }
    }

or use this in a plugin:

    def doWithSpring = {   auditListener(AuditEventListener)   hibernateEventListeners(HibernateEventListeners) {
          listenerMap = ['post-insert':auditListener,
                         'post-update':auditListener,
                         'post-delete':auditListener]
       }
    }

#### Automatic timestamping

The examples above demonstrated using events to update a `lastUpdated` and `dateCreated` property to keep track of updates to objects. However, this is actually not necessary. By merely defining a `lastUpdated` and `dateCreated` property these will be automatically updated for you by GORM.

If this is not the behaviour you want you can disable this feature with:

    class Person {
       Date dateCreated
       Date lastUpdated
       static mapping = {
          autoTimestamp false
       }
    }

> If you put `nullable: false` constraints on either `dateCreated` or `lastUpdated`, your domain instances will fail validation - probably not what you want. Leave constraints off these properties unless you have disabled automatic timestamping.