Cascade is not working - jpa

I've read about jpa cascade but still have a question.
ParentBiz.java
...
#OneToMany(cascade = {CascadeType.ALL}, mappedBy = "parent", fetch = FetchType.LAZY, targetEntity = ChildrenBiz.class)
private List<Child> children;
...
Child.java
...
#ManyToOne(targetEntity = ParentBiz.class, fetch = FetchType.LAZY)
#JoinColumn(name = "ID_PARENT", nullable = false)
#ForeignKey(name = "FKMAW53A")
private Parent parent;
...
Simple, right? I've wrote a test inserting a parent (and its children, by cascade) and it works ok. Then I add a child on parent and merge the parent, and it works ok too. But when I remove a child and merge the parent, it's not cascading.
As far as I know, it should remove all children and insert it again every time I merge the parent, but that's not what is happening. I'm really clueless, cause it seems easy...

It cannot cascade the merge request to the child because it is not in the Parent's children collection to cascade to. So the provider cannot see any changes made to children not in the list. Because the child owns the relationship, it cannot be changed from the parents side, and the relationship will continue to exist in the database.
If you want the child to be removed from the database, you will need to use orphan removal. This will cause any elements removed from the collection to be deleted from the database. But there should be no other references to the child, and its not a great measure to take if these child entities are meant to be independent from their parents or can be swapped around.
Another solution is to explicitly merge children once they are removed from their parents. If that is not possible, you might change the relationship to be unidirectional and go from the parent to the child. This will allow the parent to control the foreign key, so that changes to the collection cause the changes to be reflected in the database.

Related

After delete Member the Relation is not deleted

I have a problem with orphanRemoval. When I Delete Member and if there is no others Members referenced relation given, this relation should be deleted. But this is not the case. There is the moyen to do this with JPA configs, or I should write logic in Service ?
public class Member {
#ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
public RelationEntity getBornRelation() {
return bornRelation;
}
}
public class Relation {
#OneToMany(fetch = FetchType.EAGER, orphanRemoval = true, cascade = CascadeType.ALL)
#JoinColumn(name = "bornrelation")
public List<MemberEntity> getChildren() {
return children;
}
}
First of all, you've defined two separate associations between Member and Relation. I suspect that wasn't intentional. If you want to keep the association bidirectional, you need to make the 'one' side the owning side of the association by adding mappedBy="bornRelation" to the #OneToMany. Otherwise, changes to Member.bornRelation will not be reflected in Relation.children and vice versa.
Secondly, do not use CascadeType.ALL with #ManyToOne. CascadeType.ALL implies CascadeType.REMOVE and an attempt to remove the 'one' side of the association will fail as long as the 'many' side still contains other child entities that refer to the parent entity. JPA will not check if the deletion is possible. It will simply issue a DELETE to the database, resulting in constraint violations.
(you can keep using CascadeType.ALL with #OneToMany, but remember that you still need to make sure Member.bornRelation is set properly when adding new elements to Relation.children. JPA will not take care of that for you)
I believe the above already answers your question. What you want cannot be done by JPA configuration only, you need additional logic to check whether the Relation to delete is the last child of its parent entity. This, by the way, has nothing to do with orphan removal. Orphan removal is about removing child entities (and not parent entities).

Delete grandchild and child when entity is deleted

I have a Application_Product entity with id as applicationProductId. Credit_Card is the child of Application_Product with id same as Application_Product i.e. applicationProductId (One to One) relationship. Children of Credit_Card is named as Supplimentary_Card with id supplimentaryCardId and foriengn key as applicationProductId of Credit_Card Entity. Cascade, orphan removal is implimented at entity level hence deleting Application_Product should delete Supplimentary_Card . But is not happening. why?
Mark the relevant #OneToOne/#OneToMany/#ManyToMany annotations the following property:
#OneToMany(cascade = CascadeType.ALL)
This should ensure all children and grandchildren are removed when the parent is deleted.

JPA with eclipse link not loading child records for first time

Hi I have one table VariantValidityBE
It has a relationship column like this
#OneToMany(mappedBy = "variantValidityBE", fetch = FetchType.LAZY)
private List<VariantValidityValueBE> variantValidityBEList;
And in another table
#ManyToOne
#JoinColumn(name = "CATEGORY_ID", referencedColumnName = "ID")
private VariantValidityBE variantValidityBE;
And my method is like this
List<VariantValidityBE> resultList = getResultList(VariantValidityBE.FIND_ALL);
for (VariantValidityBE variantValidityBE : resultList) {
List<VariantValidityValueBE> options = variantValidityBE.getVariantValidityBEList();
}
the value of option is coming old value, newly inserted child record is not coming
Values are inserted into DB correctly.
But if I restart the application its giving the updated records.
The same type of relations I used so many times, never get such type problem.
Since JPA entities are treated as regular java objects, you are required to keep both sides of bidirectional relationships in synch with each other when making changes. JPA will not perform magic to mirror changes made to one side of a bidirectional relationship to the other for you. So when you add a new VariantValidityValueBE instance and set its variantValidityBE, you must also add the VariantValidityValueBE to the variantValidityBEList. Otherwise, the variantValidityBEList will remain unchanged and stale until it is refreshed from the database.

JPA: Cascading on shared objects

Say i have class called Record, with a many-to-one relationship to a class called Artist.
If i define a cascade option as such:
class Record{
#ManyToOne(cascade = CascadeType.ALL)
private Artist artist;
...
}
Say i have a number of records managed by my EntityManager and some of these share the same Artist.
What happens when i call, update, merge, detach, remove and so on on the Record objects?
Will the artist be removed for example? Will it be detached? If so, what happens to the other Record classes that references that Artist?
Since you configured the association with cascade = CascadeType.ALL, all the operations done on a record will also be done on the associated Artist. Removing the record will thus remove the artist. This will fail with a foreign key constraint exception (if they're correctly configured in the database) if another record also references the same artist.
Configuring such a cascade on a ManyToXxx associations doesn't make much sense.

CascadeType.Persist not working with primary key generator type table in JPA

I have an issue using CascadeType.Persist for my JPA/Standalone project. I have a Parent entity which has a List of Child entities that should be persisted along with the Parent and the primary key of Parent is generated using the Table(GeneratorType.TABLE) and I use a table to generate the Primary Key.
In Parent I have :
#OneToMany(mappedBy="parent",fetch=FetchType.EAGER,cascade= {CascadeType.PERSIST,CascadeType.DETACH})
List<Child> children;
//Getter and Setter
#PostPersist
public void setParentID(){
System.out.println("Inside Postpersist");
for(Child ch : this.children){
ch.setParent(this);
System.out.println(ch.getParent().getParentId());
}
}
In Child :
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "Parent_ID")
private Parent parent;
In the DB I have a not null set to Parent_ID column of the Parent table. When I persist a Parent entity and it has been set with list of Child entities it throws a
ConstraintViolationException: Cannot insert the value NULL into column 'Parent_ID', table 'jpaTest.Child', column does not allow nulls.
as the Parent is null for all the Child entities though it prints the ParentId set to every Child entity in the method annotated with #PostPersist
However this does not occur and persistence of parent and child takes place when I change the primary key generation strategy from TABLE type to AUTO. How and why is this happening.
The provider is Hibernate. And my DB server is the mssql.
That approach looks little bit weak, because specification does not give too much support for modifying other entities in life cycle callbacks:
In general, the lifecycle method of a portable application should not
invoke EntityManager or Query operations, access other entity
instances, or modify relationships within the same persistence
context.
Additionally, you do not have guarantee about order of cascade to children and #PostPersist in parent:
It is implementation-dependent as to whether callback methods are
invoked before or after the cascading of the lifecycle events to
related entities. Applications should not depend on this ordering.
Yes It worked without omitting the cascade-persist. All i had to do was set the Parent object to the Child while adding Child entities to the list of children in Parent as it is a bidirectional relationship.
In the Parent:
public void setParentToChild(Child ch){
if(this.getChildren()==null){
this.children = new ArrayList<Children>();
}
this.children.add(cb);
//this is what worked. Also set the Parent to Child
cb.setCustomer(this);
}
Now while creating new Parent and Child i call this method to add child to parent. And JPA does the rest nothing to set in the business code. Thanks to you guys.
My guess is that the child's parent field must be initialized before persisting the parent, and not after, in the #PostPersist method, which is probably called after the cascade has been done.