I have a problem with hybernate
I have 2 classes like that :
public Class Race {
#OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="race", orphanRemoval = true)
private List<Lap> laps = new ArrayList<>(0);
...
}
public Class Lap {
#ManyToOne(fetch = FetchType.LAZY, cascade=CascadeType.REFRESH)
#JoinColumn(name = "RACE_ID", nullable = false)
private Race race;
#OneToOne(mappedBy = "nextLap", fetch = FetchType.LAZY)
private Lap previousLap;
#OneToOne(fetch = FetchType.LAZY, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#JoinColumn(name = "NEXT_ID")
private Lap nextLap;
...
}
In my database I also have a unique constraint with NEXT_ID and RACE_ID
My problem is when I want to delete my Race, with
txn = session.getTransaction();
txn.begin();
race = session.merge(race);
session.remove(race);
session.flush(); //=>Exception here
txn.commit();
I get the result:
javax.persistence.PersistenceException:
org.hibernate.exception.ConstraintViolationException: could not
execute batch at
org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154)
at
org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181)
at
org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:188)
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1364)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1347)
at
package.DAORace.deleteRace(DAORace.java:122)
Caused by: java.sql.BatchUpdateException: ORA-00001: unique constraint
(LAP_UK1) violated
Hibernate do an update on my lap when I delete the race and my contraint is violated.
My question is how to delete children properly, without update, when I delete parent ?
Note : If I have only one child, I can delete it without any exception, if I have 2 or more children, I have an exception.
Thank you for your help !
For removing entities as a cascade, the best approach is removing them with a few queries.
For example:
em.createQuery("delete from Lap p where p.race.id = :id).setParameter("id", id).executeUpdate();
em.createQuery("delete from Race r where r.id = :id).setParameter("id", id).executeUpdate();
https://thorben-janssen.com/avoid-cascadetype-delete-many-assocations/ read here for better understanding.
Related
I have 2 entities like this:
#SQLDelete(sql = "UPDATE parent_table SET deleted = true WHERE id = ?")
public class Parent {
private boolean deleted;
#OneToMany(cascade = CascadeType.ALL)
#JoinColumn(name = "parent_id")
private List<Child> children;
// other stuff
}
#SQLDelete(sql = "UPDATE child_table SET deleted = true WHERE id = ?")
public class Child {
private boolean deleted;
// stuff
}
As you can see, its a unidirectional #OneToMany mapping and both entities use soft delete with the #SQLDelete annotation.
I'm trying to soft delete the parent and in turn want the child to be soft deleted as well.
When I try to soft delete , it sets the deleted flag to true in both tables and that's what I want.
However, the parent_id in the child_table is set to null when I perform the delete. Why is this happening and how can I stop this ?
The delete operation :
Parent parent= entityManager.find(Parent.class, id);
entityManager.remove(parent);
You need to:
Replace #OneToMany(cascade = CascadeType.ALL) with #OneToMany(cascade = CascadeType.PERSIST).
Add nullable = false to #JoinColumn(name = "parent_id") annotation.
I'm not sure if what you want is possible, but you could try adding this to your mapping:
#OnDelete(action = OnDeleteAction.NO_ACTION)
Maybe with this Hibernate won't change the relationship.
As a workaround you can turn off cascade delete and manually delete the children
I want to delete Recipe (using spring data DAO) but I got SQL exception: org.postgresql.util.PSQLException: ERROR: update or delete on table "recipe" violates foreign key constraint "fkacys689tmdmfggtf4thdoc83k" on table "favourite_recipes"
Detail: Key (id)=(76823) is still referenced from table "favourite_recipes".
My entities:
#Entity
public class Account {
#ManyToMany(fetch = FetchType.LAZY)
#JoinTable(name = "favourite_recipes",
joinColumns = #JoinColumn(name = "account_id"),
inverseJoinColumns = #JoinColumn(name = "recipe_id"))
private Set<Recipe> favouriteRecipes = new HashSet<>(0);
...
}
#Entity
public class Recipe {
...
}
How to remove recipe instance?
You need to handle the cascade type, by default is set to ALL.
For example you can work around the contraints like this:
#ManyToMany(cascade = CascadeType.DETACH)
more info : cascade type docs
in you need to delete from the owning entity side which is the Account.
So first remove the recipe from recipe list in Account and save the account, then remove the recipe itself.
As Amer Qarabsa metioned I had to remove recipe from Account.
I added new field in Recipe to get bidirectional mapping
#ManyToMany(cascade = CascadeType.MERGE, mappedBy = "favouriteRecipes")
private Set<Account> recipeLovers = new HashSet<>(0);
Code in service class to remove recipe from all accounts + clear lovers in recipe (recipe and recipeId variables are not initialized here)
Set<Account> recipeLovers = recipe.getRecipeLovers();
recipeLovers.forEach(account ->
account.getFavouriteRecipes()
.removeIf(r -> r.getId() == recipeId));
recipeLovers.clear();
recipeDao.delete(recipe);
I am getting the following expection:
org.springframework.orm.jpa.JpaSystemException: Batch update returned unexpected row count from update [0]; actual row count: 3; expected: 1; nested exception is
org.hibernate.jdbc.BatchedTooManyRowsAffectedException: Batch update returned unexpected row count from update [0]; actual row count: 3; expected: 1
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:314) ~[spring-orm-4.2.4.RELEASE.jar:4.2.4.RELEASE]
This occurs when I try to cascade delete an entity (Kennel) that has a one to many relationship to another entity (Dog).
Deletion code (using CRUD repository delete method):
kennelRepository.delete(kennelEntity);
Kennel Entity (Parent):
#Entity
#Table(name = "KENNEL")
public class Kennel implements Serializable
{
//other fields and getters/setters
#OneToMany(mappedBy = "kennel", cascade = CascadeType.ALL, fetch = FetchType.LAZY, orphanRemoval = true)
private List<Dog> dogList = new LinkedList<Dog>();
Dog Entity (Child):
#Entity
#Table(name = "DOG")
public class Dog implements Serializable
{
//other fields and getters/setters
#ManyToOne
#JoinColumns({
#JoinColumn(name = "KENNEL_ID", referencedColumnName = "KENNEL_ID"),
#JoinColumn(name = "KENNEL_NUMBER", referencedColumnName = "KENNEL_NUMBER")
})
private Kennel kennel;
What could be causing this? I am almost certain that the mappings are correct?
I also tried changing the fetch type from LAZY to EAGER but same error.
1.This can happen in case where the entity has already been deleted manually from the backend database and hibernate is trying to delete it again.
2.Just check if there is no other process which is deleting the records
Parent Entity
#OneToMany(fetch = FetchType.EAGER, mappedBy = "paramRef", cascade=CascadeType.ALL)
public Set getParamList() { return this.paramList; }
Child Entity
#ManyToOne(fetch = FetchType.EAGER) #JoinColumn(name = "param_Ref_Id", nullable = false, insertable=false, updatable=false)
public ParamRef1 getParamRef() { return this.paramRef; }
Code to persist
ParamRef1 pr = new ParamRef1();
pr.setName("TEST PARAM");
Param1 p1 = new Param1() p1.setParamValue("ONE") p1.setParamRef(pr);
Param1 p2 = new Param1() p2.setParamValue("TWO") p2.setParamRef(pr);
Set paramList = new HashSet() paramList.add(p1) paramList.add(p2)
pr.setParamList(paramList)
pr = paramRefDao1.save(pr)
Please let me know if the steps are correct. I am getting following exception. and not able to understand why parent id is not available in child table
Caused by: org.hibernate.exception.ConstraintViolationException:
Cannot insert the value NULL into column 'PARAM_REF_ID', table
'PARAM'; column does not allow nulls. INSERT fails.
You are missing value for the column PARAM_REF_ID for the parent table
ParamRef1 pr = new ParamRef1();
pr.setName("TEST PARAM");
pr.setParamRefId(1); // replace 1 with any other valid id as value
In my entities I have to use fetch = FetchType.EAGER because I have a mistake:
nested exception is org.hibernate.LazyInitializationException: failed
to lazily initialize a collection of role:
"field should haver FetchType.EAGER",
could not initialize proxy - no Session
If I use this then my app goes correct, but the time execution is too, between page and page around 7 seconds (now bbdd has little data)
I have two problems.
If I put FetchType.LAZY my app does not work
If I put FetchType.EAGER my app has a lot of time of execution
PF.class (Entity)
#OneToMany(fetch = FetchType.EAGER, mappedBy = "pf", cascade = CascadeType.ALL)
private Set<HDSEntity> hardwareDeviceStocks = new HashSet<HDSEntity>();
#OneToMany(fetch = FetchType.EAGER, mappedBy = "pf", cascade = CascadeType.ALL)
private Set<BSEntity> bS = new HashSet<BSEntity>();
#OneToMany(cascade = CascadeType.ALL, mappedBy = "pf", fetch = FetchType.EAGER)
private Set<CEntity> cp = new HashSet<CEntity>();
HDS.class (Entity)
#ManyToOne(cascade = {CascadeType.ALL})
#JoinColumn(name = "fk_pf")
private PFEntity pf;
BS.class (Entity)
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "fk_pf")
private PFEntity pf;
Thanks. ;)
Try reading this related question, which is almost the same issue you are facing:
Hibernate Criteria returns children multiple times with FetchType.EAGER
According to the answers given on the question above what is correct to do is keep using the EAGER fetch type to avoid the LazyInitiationException, however you must review your select queries and add some OUTER JOINs to reduce the query result.
It's really important to understand that this behavior on hibernate also occurs in native SQL queries, and that's because of it your pagination is so slow. Try to study some SQL OUTER JOINs too to minimize your pagination execution time.
Try to use FetchType.LAZY, but correct your queries with inner join fetch.