Get original values from entity with Hibernate Envers - spring-boot

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.

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).

Update only "changed values" for an existing entity

I am creating a rest API to update my entity with the new changes, but my entity is having like 20 attributs and i don't think it's a good way to just put multiple sets and "if" conditions to not set old values with NULL.
I want to know if there is a way in spring that can update the whole entity without changing the old unchanged values to null instead of putting a lot of Setters (~20 in my case).

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

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.

Update EF model - DB at different location

I am very new to EF programming.
My application gets the data from existing database. (DB first)
Now I have come to situation where I want to update my model to newer DB. basically the core schema is same as previous but has some modification in the table.
When I change the DB name for app.config and update the model it gives list of error
have I missed something?
When you do an update it merges the model you have with the DB that you update from. Additional columns are added to your existing entities but columns that you have removed from the DB are not removed from your entities and you need to remove these mappings yourself.
If you know which tables have columns removed it sometimes easier to delete the entity from your model and then do an update to reload it from the DB.
If you've don't know what tables or there have been many then it may be easier to delete all entities from your model and just do a full Update to reload the the new DB structure.

Force Hibernate to issue DELETEs prior to INSERTs to avoid unique constraint violations?

Background: http://jeffkemponoracle.com/2011/03/11/handling-unique-constraint-violations-by-hibernate
Our table is:
BOND_PAYMENTS (BOND_PAYMENT_ID, BOND_NUMBER, PAYMENT_ID)
There is a Primary key constraint on BOND_PAYMENT_ID, and a Unique constraint on (BOND_NUMBER, PAYMENT_ID).
The application uses Hibernate, and allows a user to view all the Payments linked to a particular Bond; and it allows them to create new links, and delete existing links. Once they’ve made all their desired changes on the page, they hit “Save”, and Hibernate does its magic to run the required SQL on the database. Apparently, Hibernate works out which records need to be deleted, which need to be inserted, and leaves the rest untouched. Unfortunately, it does the INSERTs first, then it does the DELETEs.
If the user deletes a link to a payment, then changes their mind and re-inserts a link to the same payment, Hibernate quite happily tries to insert it then delete it. Since these inserts/deletes are running as separate SQL statements, Oracle validates the constraint immediately on the first insert and issues ORA-00001 unique constraint violated.
We know of only two options:
Make the constraint deferrable
Remove the unique constraint
Option 2 is not very palatable, because the constraint provides excellent protection from nasty application bugs that might allow inconsistent data to be saved. We went with option 1.
ALTER TABLE bond_payments ADD
CONSTRAINT bond_payment_uk UNIQUE (bond_number, payment_id)
DEFERRABLE INITIALLY DEFERRED;
The downside is that the index created to police this constraint is now a non-unique index, so may be somewhat less efficient for queries. We have decided this is not as great a detriment for this particular case. Another downside (advised by Gary) is that it may suffer from a particular Oracle bug - although I believe we will be immune (at least, mostly) due to the way the application works.
Are there any other options we should consider?
From the problem you described, it's not clear if you have an entity BondPayment or if you have a Bond linked directly to a Payment. For now, I suppose you have the link between Payment and Bond through BondPayment. In this case, Hibernate is doing the right thing, and you'll need to add some logic in your app to retrieve the link and remove it (or change it). Something like this:
bond.getBondPayment().setPayment(newPayment);
You are probably doing something like this:
BondPayment bondPayment = new BondPayment();
bondPayment.setPayment(newPayment);
bondPayment.setBond(bond);
bond.setBondPayment(bondPayment);
In the first case, the BondPayment.id is kept, and you are just changing the payment for it. In the second case, it's a brand new BondPayment, and it will conflict with an existing record in the database.
I said that Hibernate is doing the right thing because it threats BondPayment as a "regular" entity, whose lifecycle is defined by your app. It's the same as having a User with a unique constraint on login, and you are trying to insert a second record with a duplicate login. Hibernate will accept (it doesn't knows if the login exists in the database) and your database will refuse.

Resources