What is the best way to implement soft delete in spring data and on delete that should also trigger hibernate events
There is an example on how to implement soft deletes in the Hibernate ORM documentation:
#SQLDelete(
sql = "UPDATE person SET valid = false WHERE id = ? "
)
public static class Person {
#Id
#GeneratedValue
private Long id;
private String name;
...
}
Related
I have a spring boot application with database and entity with #Transcient field... here you have a sample code:
#Entity
#Table(name = "dogs")
#JsonInclude(Include.NON_NULL)
#ApiModel
public class Dog {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int id;
#Transient
public Boolean happy;
}
Dog dog1 = dogsRepository.findById(1);
dog1.setHappy(true);
Dog dog2 = dogsRepository.findById(1);
System.out.println("dog2 is happy = " + dog2.isHappy());
and the last line prints dog2 is happy = true on the screen. How it is possible? #Transient fields are not persisting in a database.
The method dogsRepository.findById checks the 1st level cache. If it cannot be found there it will be fetched from the database and stored in the 1st level cache. That is why the 2nd call to findById will not retrieve it from the database but from the cache instead. That is why dog1 and dog2 are the same object in your case.
That will not happen for example if you clear the cache between the findById calls or execute the calls in different transactions.
I'm using SpringBoot 2.2.6 with JPA and I'm run into following problem:
#Transactional
public void batch() {
....
....
repository.save(data) // this is an update
....
....
repository.save(data) // this is a normal save
}
the Hibernate logging says to me that the save is executed before the update and this generate a constraint violation error on my db.
Do you have some idea why happend something like this?
Thanks
UPDATE
The Entity is something like this, clearly there are other Entity nested but the logic is similar
#Id
#Column(name="id")
#GeneratedValue(generator = "domande_dom_stati_domanda_id_seq", strategy = GenerationType.SEQUENCE)
#SequenceGenerator(name = "domande_dom_stati_domanda_id_seq", sequenceName = "domande_dom_stati_domanda_id_seq",allocationSize=1)
private Integer id;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne
#JoinColumn(name="id_dom_stato_domanda", nullable=false)
private DomStatoDomanda domandaStatoDomanda;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne
#JoinColumn(name="id_domanda", nullable=false)
private Domanda domande;
#Temporal(TemporalType.DATE)
#Column(name="data_validita")
private Date dataValidita;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="data_registrazione")
private Date dataRegistrazione;
#Temporal(TemporalType.TIMESTAMP)
#Column(name="data_registrazione_fine")
private Date dataRegistrazioneFine;
#Column(length=50)
private String utente;
#Column(length=250)
private String note;
#Audited(targetAuditMode = RelationTargetAuditMode.NOT_AUDITED)
#ManyToOne
#JoinColumn(name="id_ruolo", nullable=false)
private Ruolo ruolo;
JPA/Hibernate queues the operations in its session whenever possible, does not call the database instantly and then just before the transaction is completing, order those operations based on type and execute them. This is called Transactional write-behind in hibernate. As you can see, even though you called the insert last, hibernate will order it as first if it was queued.
Inserts, in the order they were performed
Updates
Deletion of collection elements
Insertion of collection elements
Deletes, in the order they were performed
You can tell hibernate to flush it rather than queue it. So replace repository.save(data) with repository.saveAndFlush(data) so it executes in the order you wanted
Reference
Executions Order
i have archive table that i don't want to be deleted so how to use jpa or hibernate to prevent the deletion of the table (delete method must throw an error), or when deleting actually do update (state = deleted). Is there any annotation or any technique to do so?
You can use entity callback #PreRemove and throw runtime exception.
https://docs.jboss.org/hibernate/orm/4.0/hem/en-US/html/listeners.html
The #SqlDelete annotation allows you to override the default DELETE statement executed by Hibernate, so we substitute an UPDATE statement instead. Therefore, removing an entity will end up updating the deleted column to true
#SQLDelete(sql = "UPDATE tag SET deleted = true WHERE id = ?")
#MappedSuperclass
public abstract class BaseEntity {
private boolean deleted;
}
#Entity(name = "Tag")
#Table(name = "tag")
#SQLDelete(sql =
"UPDATE tag " +
"SET deleted = true " +
"WHERE id = ?")
public class Tag extends BaseEntity {
#Id
private String id;
//Getters and setters omitted for brevity
}
i've spring and hibernate project in that i configured audit for Table and its working fine but my problem is i want to avoid audit at time of creating new record but while doing updating it should audit below my code
Entity:
#Entity
#Table(name = "building")
#Audited
public class BuildingClass extends CommonTableFields {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "BID")
#JsonProperty
private long id;
#JsonProperty
private String username;
#JsonProperty
private double count;
//getters and setters
}
implementation:
// here i don't want to audit
#Override
public void save(BuildingClass buildingclass) {
repo.save(buildingclass)
}
// here i want to audit
#Override
public void update(BuildingClass buildingclass) {
repo.save(buildingclass)
}
thanks in advance
It is going to depend on what strategy your using for auditing.
The DefaultAuditStrategy should work by simply not registering post-insert event listener. You would do this by registering your own envers integrator that doesn't register that specific event handler.
The ValidityAuditStrategy will be a bit of a problem. The problem here is that this strategy performs a set of update operations internally when a row is modified and those operations expect the initial insert audit row to exist and will fault if it does not.
You could override this strategy with a custom one that disables this check, but understand the check was added to detect data issues with the audit rows rather than using assumptions.
But the key to all this is conditional auditing, see reference documentation for information.
There is a problem about generating id while persisting into database.
I added the following code to my jpa entity file, however I'm getting 0 for personid.
#Id
#Column(unique=true, nullable=false, precision=10, name="PERSONID")
#SequenceGenerator(name="appUsersSeq", sequenceName="SEQ_PERSON", allocationSize=1)
#GeneratedValue(strategy=GenerationType.SEQUENCE, generator = "appUsersSeq")
private long personid;
EjbService:
#Stateless
public class EjbService implements EjbServiceRemote {
#PersistenceContext(name = "Project1245")
private EntityManager em;
#Override
public void addTperson(Tperson tp) {
em.persist(tp);
}
}
0 is default value for long type. The id will be set after invoking select query for the related sequence, which commonly is executed when you persist the entity. Are you persisting the entity? In case yes, post the database sequence definition to check it.