Spring data JPA with H2 database not returning non-merged data - spring

I have an entity with created_date (updateable = false) and updated_date fields. I have #PreUpdate method where I change the updated_date value only (not change created_date), and #PrePersist method which sets new created_date and updated_date values. On Persist the created_date and updated_date are rightly persisted and the returned entity has the correct values. When I pass in the entity to merge, it rightly updates the updated_date (#PreUpdate), and I don't pass the created_date in input. In the database the right updated_date value is updated and created_date value is not changed rightly. But the returned entity has the created_date value set to null. Any Ideas why? Shouldn't the merged entity return the full entity loaded from the database?
Thanks
Sam

I think that is inline with the JPA merge javadoc.
Merge - Merges the state of the given entity into the current persistence context and returns the managed instance that the state was merged to.
(With hibernate as persistence provider) Merge starts with loading the data from the database for that entity, then copies detached entities state to the newly loaded entity. Subsequently, at a later point, during the transaction commit phase(or flush) the dirty checking mechanism fires the update query but won't include the fields marked as updatable=false.
So it doesn't attempt to reload the object with the data in the database after the UPDATE.
To trigger reload, you can rely on refresh(...) that will reload the data.
If it is spring-data-jpa it doesn't expose any refresh method, so you need to add it to your repository and and an example can be found here and discussion on this topic in the spring forum here.

Related

spring-data jpa's deleteAll() method call records are not audited in hibernate envers

By default for save(), delete(), saveAll() hibernate envers audit the record change.
But for deleteAll() it is not auditing.
In application.properties override org.hibernate.envers.store_data_at_delete
org.hibernate.envers.store_data_at_delete = true
Default value is false
"org.hibernate.envers.store_data_at_delete" Should the entity data be stored in the revision when the entity is deleted (instead of only storing the id and all other properties as null). This is not normally needed, as the data is present in the last-but-one revision. Sometimes, however, it is easier and more efficient to access it in the last revision (then the data that the entity contained before deletion is stored twice).

when more foreign keys and need to insert is it good to use native #Query instead of JPA managed way

There is a table with 3 foreign keys to three tables.
To do an insert using JPA, is it suggested/performant to
query individual tables(having foreign key relations) and create
respecitve objects and do a .save()
?
or
use native #Query(), with #Transactional and #Modifying?
for making an insert, i am making 3 calls to DB to get respective objects/details and use them for insertion. so total 4 calls.
If i use native Query, i have the id's required(getting from client) i can do it in one query.
so, is it good to do in JPA way or use native query? which is good in view of performance?
If you have the primary keys of the dependencies you can call EntityManager.getReference().
This will return a placeholder that you can use to set as the dependencies in your entity. That way no SQL statement is executed for the dependencies.
From the API Doc:
<T> T getReference(Class<T> entityClass,
Object primaryKey)
Get an instance, whose state may be lazily fetched.
If the requested instance does not exist in the database, the EntityNotFoundException
is thrown when the instance state is first accessed.
(The persistence provider runtime is permitted to throw the EntityNotFoundException when getReference is called.)
The application should not expect that the instance state will be available upon detachment,
unless it was accessed by the application while the entity manager was open.
Parameters:
entityClass - entity class
primaryKey - primary key
Returns:
the found entity instance
Throws:
IllegalArgumentException - if the first argument does not denote an entity type or the second argument is not a valid type for that entity's primary key or is null
EntityNotFoundException - if the entity state cannot be accessed
https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#getReference-java.lang.Class-java.lang.Object-

How does Spring-data handle/retrieve data populated by triggers and not by itself?

I have a problem with Spring Data + MySQL triggers.
Currently, before a new row is inserted in a table, a MySQL trigger assigns data to specific columns:
Table User
Columns created_at and updated_at
Those columns are mapped as follow:
#Column(name = "created_at")
private Date createdAt;
#Column(name = "updated_at")
private Date updatedAt;
Likewise, I have a service (annotated as #Transactional) which populates with data the instance User but created_at and updated_at, I mean, when I'm calling save for the userRepository those attributes go as nulls.
MySQL before to insert (trigger) into DB, both attributes are populated with the MySQL function utc_timestamp().
My problem:
Just after I call the service saveUSer, I'm calling findById from the repository. Why both attributes created_at and updated_at has null value in the instance (in db they have values)?
After saving an user , the instance will be cached inside the EntityManager. If the call of findById is still in the same transaction that is used to save the user , it will just return that user instance that is cached inside the EntityManager which the createdAt and updatedAt are null.
In JPA , we can call entityManager.refresh(user) to force selecting that user from the DB such that the user instance managed by JPA will have the latest values as the DB record. So you can use entityManager.refresh(user) after saving the user to ensure the latest value of createdAt and updatedAt are updated back to the user instance managed by JPA.
However , Spring data 's JPA repository does not expose EntityManager 's refresh, you can extend it like this.
The other answer quite accurate, however it assumes you call saveUser and findById from inside an a transaction.
However when you use Spring Data JPA under Spring Boot this issue could happen even if you are out of a transaction.
Spring Boot has a default setting which automatically encapsulates each request in a transaction.
So, if you use Spring Boot it would worth a try to add the following line to the application.properties:
spring.jpa.open-in-view=false

Treat Entity with Id NULL as NEW

To the question "Save Differences with Entity ID" I found the following answer:
"For Entities, Id property cannot be null, so you need to map this class as ValueObject. If so,
Id property is treated as regular property and it not goes to GlobalId of this object."
My question is:
Why can't an entity be treated as NEW if the Id is NULL?
I have an object graph that is fetched from the database, and between two javers commits an entity is added to a list in the graph.
Two commits and in the second commit there is a new entity (Id NULL)
Get the change => exeption because Javers can't create a GlobalId.
I can get arround this by doing EntityManager - persist (creates Id:s), but I would like to avoid doing that. The present code may do a persist later or it just lets the transaction finish.
Because the Id is NULL, the entity is NEW. Would it be possible to generate a unigue temp Id (allow Id = NULL) to be able to create the GlobalId?
In the change list, the entity would be reported as NEW. No need to compare with earlier commits.
You should compare/commit your objects when they are fully initialized so when they have Ids.
An entity without Id can't be handled by JaVers for several reasons:
it can't be compared to other entity/version (diff algorithm is based on GlobalIds)
it can't be queried from JaVersRepository (queries use GlobalIds)
If you are using Hibernate, compare/commit your new objects after Hibernate assigns them Ids from sequences.
Another options:
don't use sequence-generated values as JaVers Id but some business identifiers
if an Entity doesn't have a business identifier you can generate UUID in a constructor and use it as JaVers id (and also database PK if you like)

Get original values from entity with Hibernate Envers

I have configured Hibernate Envers in my Springboot project and now it is saving each change in the entities I annotated with #Audited but, I have a doubt.
Envers stores the revision of the entity after the first change is done so, after one change I have the new values stored in the entity table and in the _AUD table. The next changes are stored in the _AUD table so I know what changed after the first update but the original values (the ones before the first change) are lost. Am I missing something? Is there a way to save the values before the change is done (as I already have the last values in the entity table)?.
There are three different revision types tracked by Envers:
ADD (REVTYPE=0) - INSERT
MOD (REVTYPE=1) - UPDATE
DEL (REVTYPE=2) - DELETE
This implies that if the entries are being inserted, updated, and deleted by Hibernate through a stateful session, Envers will pickup those changes and add the appropriate REVTYPE entry to the audit table.
If an entry is being manipulated outside of the scope of Hibernate's stateful session, Envers won't know about that change and the corresponding entry won't be added to the audit table. Based on the comments, this is why you don't see a REVTYPE=0 (aka INSERT) operation.
For situations like this, you'll need to make sure that you increment the revision number sequence and add the appropriate entries manually through your script or batch process that is inserting the row in order to guarantee that the Envers schema has the complete visibility to the entity's history.

Resources