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.
Related
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).
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.
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.
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.
I am trying to import data from a database that uses primary key / foreign key relations to a core data database in Xcode.
I have code that creates hundreds of child entities in a managed object context:
Each child has an ID that corresponds to a parent.
child1 parentID = 3
child2 parentID = 17
child3 parentID = 17
...
childn parentID = 5
I now need to relate each child to its parent. The parents are all stored in persistent memory.
My first thought was to preform a fetch for each child to get its parent. However, I think this would be slow.
Am I correct? How should I do this instead?
Why are you modeling this parent-child relationship using an attribute in the child entity?
You should model this using a to-many relationship from the parent entity to the child entity, and a to-one inverse relationship from the child to the parent entity. Set on delete cascade on the to-many relationship and nullify on the to-one relationship.
Then, once you have a child object you simply use the to-one relationship to the parent entity to access the child's parent.
I have been looking at a few examples and have decided that the best approach would be the following
1) Fetch all the parents
2) Transfer them into a dictionary with their parentID as the key
Then for each child, look up its parent in the dictionary, then relate them together.