How to save child field using #RequestBody in spring-boot? - spring

I have parent and child classes.
Parent have a field:
#OneToMany(mappedBy="parent", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
Set<Child> childs;
Child
#ManyToOne(fetch = FetchType.EAGER)
#JoinColumn(name = "parent_id", referencedColumnName="id")
private Parent parent;
My controller
#PostMapping("/parent)
public Parent createParent(#RequestBody Parent parent) {
return parentRepo.save(parent);
}
it saves parent and childs info EXCEPT parent_id in the child table. parent_id is always null. Is it possible to workaround this problem without deleting mappedBy="parent" option and using additional tables?

Related

Not able fetch parent object inside a child object

I have established a one to many relationships which are working fine but there is some loophole
I.e
I'm able to fetch the parent and list of children associated with the parent (Parent by parent Id).
I'm able to fetch a child but not able to fetch the parent associated with that child not even a single field.
Inside Company Model class
#OneToMany(mappedBy = "company", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#EqualsAndHashCode.Exclude
#JsonIgnoreProperties("company")
private Set<User> users = new HashSet<User>();
Inside User Model
#ManyToOne(fetch = FetchType.LAZY, optional = false, cascade = CascadeType.ALL)
#JoinColumn(name = "company_id")
#JsonBackReference
#EqualsAndHashCode.Exclude
private Company company;
on top of company class
#Data
#Entity
#NoArgsConstructor
#EqualsAndHashCode(callSuper = true)
on top of the User class
#Data
#Entity
#AllArgsConstructor
#EqualsAndHashCode(callSuper = true)

relationship row to be deleted on cascade delete

I have the following entities in a one-to-many relationship:
#Entry
class Parent {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int id;
...
#OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Collection<Child> children;
...
}
and
#Entry
class Child {
#Id #GeneratedValue(strategy=GenerationType.AUTO)
private int id;
...
#Transient
private Parent parent;
...
}
So – out of these, there are the following 2 entity tables in the database
parent(id, ...)
child(id, ..)
and the relationship table between these two entities-- due to that #OneToMany relationship
parent_child(parent_id, child_id)
suppose parent_id=4 has the child_id=7 and thus parent_child table has the row (parent_id=4, child_id=7).
When i delete child id =7, isn’t the (parent_id=4, child_id=7) in parent_child table supposed to be deleted as part of it? I’m seeing that row in parent_child table even after the corresponding child is deleted from the child table.
I’m using the repository (implementing CrudRepository) for deleting that child.
//////////////
UPDATE:
by parent_child(parent_id, child_id), i'm referring to the relationship table that hibernate is generating behind the scenes to maintain the relationship between parent and child tables.
went into this table out of curiosity directly on SQL. and these are what i'm seeing. i expected (still do) the (parent_id=4, child_id=7) row would disappear now that child_id=7 fell off the face of the Earth. but didn't.
You have to mapped your entity class like this.
#ManyToOne
#JoinColumn(name = "parent_id", referencedColumnName = "id", nullable = false,cascade = CascadeType.ALL,fetch = FetchType.EAGER)
private Parent parent;
#OneToMany(mappedBy = "parent",cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER)
private Collection<Child> children;
Remove
#Transient
private Parent parent;
And do #ManyToOne mapping in Child Entity.

JPA Unidirectional mapping to insert list of Child entity along with Parent entity + Insert child separately

I have parent-children unidirectional relation as follows:
#Entity
#Table(name = "PARENT")
public class Parent {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int parentId;
#OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST)
#JoinColumn(name = "parent_id", nullable = false)
private List<Child> children;
}
#Entity
#Table(name = "CHILD")
public class Child {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "ID")
private int id;
#Column(name = "PARENT_ID", insertable = false, updatable= false)
private int parentId;
//some other field
}
I create an instance of the parent, assign a list of children to it and try to persist it and it works well.
Parent p = new Parent();
List<Child> children = new ArrayList<Child>();
Child c = new Child();
children.add(c);
p.addChildren(children);
em.persit(p);
em.flush();
When I try to save via Child entity separately, I see that the insert query is trying to insert null to column PARENT_ID in Child Table and results in
Child c = new Child();
c.setId(78987);
c.setParentId(12345);
em.persist(c);
em.flush();
Exception while saving Child Entity independent of Parent table. The Child entity that Im trying to insert is related to the Parent entity that exists already.
java.sql.SQLIntegrityConstraintViolationException: ORA-01400: cannot insert NULL into ("MY_SCHEMA"."PARENT"."PARENT_ID")_
Is it not possible to save Child entity directly after defining the relation as Unidirectional?
It will work when you make the change that #Shekhar Khairnar also mentioned.
It works well when you add a child to the parent but does not work when defining a child.
You would do that when the responsibility of creating/updating the referenced column isn't in the current entity, but in another
entity.
If you are going to use unidirectional and add a child object, you should remove the insertable = false definition.
However, such usage may result in data inconsistency. You should pay attention.
In addition, you do not need to give an id when defining a child, because this will be created automatically according to your model and will not take the value you give.

How to update an entity using #onetomany relationship in JPA

I created an entity using a tree structure and parent child relations using #ManyToOne and #OneToMany annotations. However only changes I made to a parent of an entity are processed in the database.
My entity class looks like this:
#Entity
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class OKR {
#Id
#Column(name = "ID")
#GeneratedValue
private UUID id;
#NotBlank
private String name;
#ManyToOne(cascade = CascadeType.ALL, fetch = FetchType.LAZY)
#JoinColumn(name = "parentid", referencedColumnName = "id")
private OKR parent;
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
private List<OKR> children;
private boolean isRoot;
public OKR(String name, OKR parent, List<OKR> children){
this.name = name;
this.children = children;
if (this.children==null){
this.children = new ArrayList<>();
}
this.parent = parent;
if (parent == null||parent.equals(new UUID(0,0))){
isRoot = true;
}else{
isRoot = false;
}
}
protected OKR(){
isRoot = true;
children = new ArrayList<>();
}
When I update an OKR by changing its parent, the parent OKR is updated as well. However when I update an OKR by only adding a child, the child OKR does not get updated. I'm fairly new to JPA and I also noticed that there is no table for children inside my database. So my question is what is the easiest way to update all relations when only updating the children of an entity?

Select Parent Entity where given set (parameter) is exact sub set of Parent's child set in ManyToMany relation in JPA Query

Let's say the Parent Entity is Parent. It has ManyToMany relation with child Child.
#Entity
public class Parent{
#ManyToMany(fetch = FetchType.EAGER)
#JoinColumn(name="child_Id")
private Set<Child> childs;
}
And Child,
#Entity
public class Child{
#ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
#JoinTable(name = "child_parent",
joinColumns = #JoinColumn(name = "child_id", referencedColumnName = "id"),
inverseJoinColumns = #JoinColumn(name = "parent_id", referencedColumnName = "id"))
Set<Parent> parents;
}
Suppose our parent entities are,
parent1 has child -> childA, childB, childC;
parent2 has child -> childB, childC;
parent3 has child -> childB, childC, childD;
parent4 has child -> childA, childC;
parent5 has child -> childA, childB, childC, childD;
Now I want to query all those parents which have childA, childC together. So, in that case, the parents will be parent1, parent4 and parent5.
(parent2 and parent3 are not accepted because they do not have childA and childC together)
My JPA Interface method signature.
List<Parent> findParentByChilds (#Param("childs") Set<Child> childs)
Here's a simple solution using SQL
SELECT parent_id
FROM child_parent
WHERE child_id IN ('childA', 'childC')
GROUP BY parent_id
HAVING COUNT(DISTINCT child_id) = 2
If a parent cannot have the same child twice (e.g. you have a unique key on (parent_id, child_id), then you could remove DISTINCT from the COUNT() aggregate function.
It should be straightforward to translate that to JPQL, or you just use a native SQL query.

Resources