Inject a method or a code before executing #Modifying spring jpa - spring

I have a scenario where the data is updated through Jpa repository.save() and also using JPQL with #Modiyfying annotations if I want to update one or two fields.
I have introduced EntityListener to perform operation on #PreInsert and #PreUpdate. This works like a charm when I use save() method.
CHALLENGE
I want to execute same code which I execute on EntityListener everytime any JPQL is executed through #Modifying annotation.
In short I want to inject piece of code for #Modifying operations.
Is there any way to do it? I searched but couldn't find one.
Thanks for the time.

Related

How to refresh Spring JPA when data is updated from querydsl directly?

I'm using spring data jpa and querydsl. I don't want to update directly through JPA because I have to submit a complete entity, which introduces an unnecessary query. So, I use querydsl instead:
val qRecord = QCoupon.coupon
jpaQueryFactory.update(qRecord)
.set(qRecord.useState, Coupon.STATE_ORDERED)
.set(qRecord.useTime, useTime)
.where(qRecord.id.eq(recordId))
.execute()
But the query after that in the same transcation cannot get the latest data, I think it has something to do with the first-level cache.
Adding #Modifying doesn't work because I didn't use #Query, the first annotation will be ignored.
I know EntityManager.clear() can fix that. But it looks too heavy, I'm not sure this is a good idea.
This post explained the cause of the problem very well but not my case -- I have rejected both two answers.
#Modifying is ignored.
EntityManager.clear() looks too heavy, and find() also need an entity.
Thanks #Jan-WillemGmeligMeyling 's idea. Because he didn't reply to me, I wrote it in my answer.
Have you tried refreshing the entity?
entityManager.refresh(entityManager.find(Coupon.class, recordId))
em.find() will not look up the entire table, that's what I want.

How to actualize entity in Spring JPA? Actualize or create new one?

I'm wondering what is best practice to update JPA entity in Spring project - update original entity or create new? I see these two approaches:
Use original - Actualize necessary fields in original entity and save this updated entity back to the repository.
Use copy - manually create new instance of entity, set all field from original entity (+ updated fields) into new entity and save the entity back to the repository.
What approach do you use / is recommended? And why?
When it comes to updating, the standard way would be to retrieve the entity reference(read below) and make changes within a transactional method:
private JpaRepository repo;
#Transactional(readOnly = false)
public void performChanges(Integer id){
Entity e = repo.getOne(id);
// alter the entity object
}
Few things regarding the example:
You would want to use the getOne method of JpaRepository as much as possible as it is in general faster than the findOne of the CrudRepository. The only trick is that you have to be sure that entity actually exists in the database with the given id. Otherwise you would get an exception. This does not occur regarding the findOne method so you would need to make that decision regarding each transactional method which alters a single entity within your application.
You do not need to trigger any persist or save methods on the EntityManager as the changes will be automatically flushed when the transaction is commited.. and that is on method return.
Regarding your second option, I dont think thats much of a use as you would need to get the data using above method anyway. If you intend to use that entity outside of the transaction, then again you could use the one retrieved from the exmaple above and then perform merge once it is again needed within the transactional context and thus Persistence Provider.
Getting an entity and then just updating that entity is the easiest way to do that. Also this is faster than a creation of a copy since EntityManager manages an entity and know that managed entity already exists in DB (so no need to execute additional query).
Anyway, there is third and the fastest approach: using executeUpdate on Query object.
entityManager
.createQuery("update EntityName set fieldName = :fieldName where id = :id")
.setParameter("fieldName", "test")
.setParameter("id", id)
.executeUpdate();
It is faster due to bypassing the persistent context

Is there a way to use UPDATE query with dynamic attributes in Spring Framework?

I'm developing a REST server application using Spring Boot.
Just got a question while constructing an UPDATE query.
Currently my UPDATE query in UserRepository is like this;
#Modifying
#Transactional
#Query(value ="update User u set u.user_dob=:userDOB, u.user_lastname=:userLastName, u.user_firstname=:userFirstname, u.user_streetaddress=:userStreetAddress where d.driver_id=:driverId", nativeQuery = true)
void updateUser(#Param("userDOB") String userDOB, #Param("userLastName") String userLastName, #Param("userFirstName") String userFirstName, #Param("userStreetAddress") String userStreetAddress);
However, I don't like to list all the attributes of User in one UPDATE query.
Is there anyway to construct UPDATE query dynamically?
For example;
Update with
set u.user_dob=:userDOB, u.user_lastname=:userLastName, u.user_firstname=:userFirstname, u.user_streetaddress=:userStreetAddress
or
u.user_lastname=:userLastName, u.user_firstname=:userFirstname
using one update method.
If you are using Spring Data JPA (seems you do), your repository interface is probably extending JpaRepository interface.
In this case, you could simply use save method.
Here are some good examples:
http://www.springbyexample.org/examples/spring-data-jpa-repository.html
http://www.springbyexample.org/examples/spring-data-jpa-code-example.html

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?
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
Since JPA 2.1 Entity Listeners are CDI managed. Have you tried using #PersistenceUnit annotation? Are you using JTA transaction type?
Otherwise you could use Persistence.createEntityManagerFactory within the Listener class to retrieve the Persistence Context.

HibernateDAOSupport Get method

I am working on a existing project which uses Hibernate and Spring. I see a following code which uses HibernateDAOSupport class,
Employee emp = getHibernateTemplate().get(Emplyee.class, 1001)
After the above line we set some property like emp.setAge(25); and at the end we don't call any Save or SaveOrUpdate method. But it's saving the data to DB. How is it possible ?
If it can Save then what is the difference between getHibernateTemplate().get() and getHibernateTemplate().save/SaveOrUpdate methods ?
This is expected behaviour of Hibernate and it is because the Employee entity is loaded into the PersistenceContext and therefore enters the 'persistent' entity lifecycle state.
When you commit the transaction, Hibernate will check any 'persistent' entities within the PersistenceContext to see if they are "dirty". Dirty means that any values of the entity have changed. Your call to emp.setAge(25) means that Hibernate understands that data within the entity has changed (it is dirty), and it should therefore make the changes persistent when the transaction commits.
It is worth reading and understanding how Hibernate manages entity states as it can be a little confusing to start with. The documentation is here.

Resources