Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create Entity by using EntityListener

I have a customer which has an association to a customerBudget entity. A CustomerEntityListener will create a customerBudget entity.

I get the following error:

IllegalStateException: During synchronization a new object was found through a relationship that was not marked cascade PERSIST: de.company.entity.Customer-c4775b5b-413b-0567-3612-e0860bca9300 [new,managed].

the code in onAfterInsert(Customer entity)

    LoadContext<Customer> loadContext = LoadContext.create(Customer.class);
    loadContext.setId(entity.getId());
    Customer customer = dataManager.load(loadContext);

    CustomerBudget customerBudget = new CustomerBudget();
    customerBudget.setCustomer(customer);

    CommitContext commitContext = new CommitContext(customerBudget);
    dataManager.commit(commitContext);

How can I create and persist Entites in an EntityListener?

like image 872
Matthias Hamann Avatar asked Apr 26 '16 12:04

Matthias Hamann


People also ask

What is @entitylistener?

Annotation Type EntityListenersSpecifies the callback listener classes to be used for an entity or mapped superclass. This annotation may be applied to an entity class or mapped superclass. Since: Java Persistence 1.0.


1 Answers

You can implement BeforeInsertEntityListener interface and create a new entity in the current persistence context via EntityManager.

The listener may look as follows:

@Component("demo_CustomerEntityListener")
public class CustomerEntityListener implements BeforeInsertEntityListener<Customer> {

  @Inject
  private Metadata metadata;

  @Inject
  private Persistence persistence;

  @Override
  public void onBeforeInsert(Customer entity) {
    CustomerBudget customerBudget = metadata.create(CustomerBudget.class);
    customerBudget.setCustomer(entity);
    persistence.getEntityManager().persist(customerBudget);
  }
}

The new entity will be saved to the database on the transaction commit together with the Customer.

The Metadata.create() method is the preferred way to instantiate entities - for entities with integer identifiers it assigns an ID from a sequence; it also handles entity extension if needed.

Entity listeners work in the transaction that saves the entity, which allows you to make atomic changes in your data - everything will be either saved or discarded together with the entity the listener is invoked on.

Unlike EntityManager, DataManager always creates a new transaction. So you should use it in an entity listener only if you really want to load or save entities in a separate transaction. I'm not sure why you get this particular exception, but your code looks weird: you load an instance of Customer which is in the database instead of using the instance which is passed to the listener. When I tried to run your code on HSQLDB, the server went to infinite lock - the new transaction inside DataManager waits until the current transaction saving the Customer is committed.

like image 137
knstvk Avatar answered Jan 01 '23 10:01

knstvk