3.4.7. EntityChangedEvent

EntityChangedEvent is a Spring’s ApplicationEvent which is sent by the framework on the middle tier when an entity instance is saved to the database. The event can be handled both inside the transaction and after its completion (using @TransactionalEventListener). The event is sent only for entities annotated with @PublishEntityChangedEvents.

EntityChangedEvent does not contain the changed entity instance but only its id. Also, the getOldValue(attributeName) method returns ids of references instead of objects. So if needed, the developer should reload entities with a required view and other parameters.

Below is an example of handling the EntityChangedEvent for a Customer entity in the current transaction and after its completion:

package com.company.demo.core;

import com.company.demo.entity.Customer;
import com.haulmont.cuba.core.app.events.AttributeChanges;
import com.haulmont.cuba.core.app.events.EntityChangedEvent;
import com.haulmont.cuba.core.entity.contracts.Id;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
import org.springframework.transaction.event.TransactionPhase;
import org.springframework.transaction.event.TransactionalEventListener;
import java.util.UUID;

@Component("demo_CustomerChangedListener")
public class CustomerChangedListener {

    @EventListener (1)
    private void beforeCommit(EntityChangedEvent<Customer, UUID> event) {
        Id<Customer, UUID> entityId = event.getEntityId(); (2)
        EntityChangedEvent.Type changeType = event.getType(); (3)

        AttributeChanges changes = event.getChanges();
        if (changes.isChanged("name")) { (4)
            String oldName = changes.getOldValue("name"); (5)
            // ...
        }
    }

    @TransactionalEventListener(phase = TransactionPhase.AFTER_COMMIT) (6)
    private void afterCommit(EntityChangedEvent<Customer, UUID> event) {
        (7)
    }
}
1 - this listener is invoked inside the current transaction. Using the @EventListener annotation is the same as @TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT).
2 - changed entity’s id.
3 - change type: CREATED, UPDATED or DELETED.
4 - you can check if a particular attribute has been changed.
5 - you can get the old value of a changed attribute.
6 - this listener is invoked after the transaction is committed.
7 - after transaction commit, the event contains the same information as before commit.

If the listener is invoked inside the transaction, you can roll it back by throwing an exception. Nothing will be saved in the database then. If you don’t want any notifications to the user, use SilentException.

When handling EntityChangedEvent in the current transaction, use TransactionalDataManager to get the current state of the changed entity from the database. In a listener invoked after transaction commit, use DataManager which will create a new transaction to load data.

Do not forget to add the @PublishEntityChangedEvents annotation to entities for which you want to listen to EntityChangedEvent.