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).
Related
I have been getting an error while trying to update a list of entities containing persisted entity and detached entity both (newly created entity) into my db using jpa2.0.
My entity contains internal entities which are giving an error (mentioned in the title) when merging the data:
Class superclass{
private A a;
private string name;
//getter setters here...
}
Class A{
private long id;
#onetoone(cascade=CascadeType.All, fetch=FetchType.Eager)
private B b;
#onetoone(cascade=CascadeType.All, fetch=FetchType.Eager)
private C c;
//getter setters here...
}
Class Dao{
daoInsert(superclass x){
em.merge(x);
}
}
I want any entity sent for persisting to be merged into the db.
Hibernate does provide solution for this by adding the following to the persistence.xml
Is there something I can do in jpa same as hibernate.
Please do not suggest to find the entity using em.find() and then update manually because I need both entities the persisted entity and the newly created entity too.
Also I'm using spring form to persist the entire patent entity into db.
I am sorry if I'm not clear enough, this is my first question and I'm really a beginner.
Any help will be most appreciated.
Found an answer to the question myself today.You just need to
remove CascadeType.MERGE from the entity that is not allowing you to persist the detached entity.
if you're using CascadeType.ALL then mention all cascade type other than CascadeType.MERGE.
Now removing CascadeType.MERGE from cascade is one solution but not a best solution because after removing MERGE from Cascade you won't be able to update the mapped object ever.
If you want to merge the Detached entity with Hibernate then clear the entity manager before you merge the entity
entityManager.clear();
//perform modification on object
entityManager.merge(object);
To solve this problem make sure to specify that the identifiers of your objects are automatically generated by adding #GeneratedValue(strategy = GenerationType.IDENTITY) on the identifaint such as id.
In this way when the merge will be carried out, the identifier of the elements to merge will be automatically incremented, compared to the other object already recorded in the database to avoid primary key conflicts
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.
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 have a many-to-many relationship where the link table has an additional property. Hence the link table is represented by an entity class too and called Composition. The primary key of Composition is an #Embeddable linking to the according entities, eg. 2 #ManyToOne references.
It can happen that a user makes an error when selecting either of the 2 references and hence the composite primary key must be updated. However due to how JPA (hibernate) works this will of course always create a new row (insert) instead of an update and the old Composition will still exist. The end result being that a new row was added instead of one being updated.
Option 1:
The old Composition could just be deleted before the new one is inserted but that would require that the according method handling this requires both the old and new version. plus since the updated version is actually a new entity optimistic locking will not work and hence last update will always win.
Option 2:
Native query. The query also increments version column and includes version in WHERE clause. Throw OptimisticLockException if update count is 0 (concurrent modification or deletion)
What is the better choice? What is the "common approach" to this issue?
Why not just change the primary key of Composition to be a UID which is auto-generated? Then the users could change the two references to the entities being joined without having to delete/re-create the Composition entity. Optimistic locking would then be maintained.
EDIT: For example:
#Entity
#Table(name = "COMPOSITION")
public class Composition {
#Id
#Column(name = "ID")
private Long id; // Auto-generate using preferred method
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn( .... as appropriate .... )
private FirstEntity firstEntity;
#ManyToOne(fetch = FetchType.LAZY, optional = false)
#JoinColumn( .... as appropriate .... )
private SecondEntity secondEntity;
....
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.