Search code examples
springoracle-databasehibernatejpaentitylisteners

How do I execute named queries from a JPA EntityListener?


I have a requirement to set a date_updated value in my database for each row when that row is updated. Let's call the entity that I'm working with Order, which has a corresponding orders table in the database.

I've added the date_updated column to the orders table. So far, so good.

The @Entity Order object that I'm working with is provided by a third party. I do not have the ability to modify the source code to add a field called dateUpdated. I have no requirement to map this value to the object anyway - the value is going to be used for business intelligence purposes only and does not need to be represented in the Java entity object.

My problem is this: I want to update the date_updated column in the database to the current time each time an Order object (and its corresponding database table row) is modified.

Constraints:

  • We are using Oracle, Spring, JPA and Hibernate
  • I cannot use Oracle triggers to update the value. We are using a database replication technology that prevents us from using triggers.

My approach thus far has been to use a JPA EntityListener, defined in xml, similar to this:

<entity-mappings xmlns="....">
  <entity class="com.theirs.OrderImpl">
    <entity-listeners>
      <entity-listener class="com.mine.listener.OrderJPAListener" />
    </entity-listeners>
  </entity>
</entity-mappings>

My listener class looks like this:

public class OrderJPAListener { 

  @PostPersist
  @PostUpdate
  public void recordDateUpdated(Order order) {
    // do the update here
  }
}

The problem I'm having is injecting any sort of persistence support (or anything at all, really) into my listener. Because JPA loads the listener via its methods, I do not have access to any Spring beans in my listener class.

How do I go about injecting an EntityManager (or any Spring bean) into my listener class so that I can execute a named query to update the date_updated field?


Solution

  • How do I go about injecting an EntityManager (or any Spring bean) into my listener class so that I can execute a named query to update the date_updated field?

    As noted above JPA 2.1 supports injecting managed beans to an Entity Listener via CDI. Whether or not Spring supports this I am not sure. The folloiwng post proposes a Spring specific solution.

    https://guylabs.ch/2014/02/22/autowiring-pring-beans-in-hibernate-jpa-entity-listeners/

    A possible alternative approach would be however to override the SQL generated by Hibernate on an update which is possible as detailed below.

    https://docs.jboss.org/hibernate/orm/3.6/reference/en-US/html/querysql.html#querysql-cud

    This would be straightforward if you had the source as you would just need to add the @SQLUpdate annotation and tag on the additional date_update column. As you don't however you would need to look at redefining the metadata for that Entity via an xml configuration file and defining the sql-update statement as outlined above:

    https://docs.jboss.org/hibernate/stable/annotations/reference/en/html/xml-overriding.html#xml-overriding-principles-entity