can i retrieve child entity containing parent entity id by using Spring Data Jpa one-to-many unidirectional relationship - spring

Here is my parent entity:
#Entity
public class Parent {
#Id
int parentId;
String name;
#OneToMany()
#JoinColumn(name="parent_id")
List<Child> childList;
}
public class Child {
int childId;
//if i am taking this property as non-transient application won't run. but i need parent Id without changing the class structure..
#Transient
int parentId;
// ... some other properties
}
Insertion is successful as two tables are created : parent(id,name),
child(id,name,parent_id).
But when I retrieve the Parent record then in the Child object, the
parentId property remains 0.

i found a way to retrieve the parentid from the child entity by doing a bidirectional mapping of the Parent-child relationship. You can get the ParentId by using a getter method from the child entity that returns the parentId.
Parent Entity
#Entity
#Table(name = "Parent")
public class Parent implements Serializable {
#Column(name = "ID", nullable = false, length = 10)
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int Id;
#Column(name = "Name")
public String name;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<Child> children = new HashSet<>();
public Parent() {
}
//getters and setters omitted for brevity
}
//Child Entity
#Entity
#Table(name = "Child")
public class Child implements Serializable{
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private int Id;
#Column(name = "Name")
private String name;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "parentId", nullable = false)
#OnDelete(action = OnDeleteAction.CASCADE)
private Parent parent;
public Child() {
}
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#JsonIgnore
public Parent getParent() {
return parent;
}
//getter method to retrieve the parent id in the child entity
public int getParent_Id(){
return parent.getId();
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
Notice the method getParent_Id() which returns the parent Id, since getter methods are used to return object, the parentId would be returned as part of the child entity anytime it is fetched.
Also note the use of #JsonIgnore on the getParent() method, this to avoid an infinite recursion going on during serialization since Parent refers to Child and Child refer to Parent.

Related

how to return relationship in spring data neo4j

Here's nodeEntity
#Data
#NodeEntity
public class Resource {
#Id
#GeneratedValue
private Long id;
#Property("name")
private String name;
private String code;
#Property("parent_code")
private String parentCode;
private String label;
private Neo4jRelationship relationship;
}
And here's relationship between nodes
#Data
#RelationshipEntity
public class Neo4jRelationship {
#Id
private Long id;
#StartNode
private Resource startNode;
#EndNode
private Resource endNode;
}
I want to query all the relationship satify some condition,
#Query("match p = (a : category_first {name: $name})-[*1..2]-() return p")
List<Neo4jRelationship> getFistCatNode(#Param("name") String name);
but the query return am empty list.
However, if I change the return type to org.neo4j.ogm.model.Result, the query can return normally.
I'm confused why the first way dosen't work. Any help will be grateful

ManyToOne with jsonb Colum

There are my classes:
Parent
#Entity
#NoArgsConstructor
#Data
#AllArgsConstructor
public class Parent {
#Id
private String id;
private String name;
private String ssn;
#Valid
#Type(type = "json")
#Column(columnDefinition = "jsonb")
#OneToMany(mappedBy="parent ", cascade = CascadeType.ALL)
private List<Child> children;
}
Child
#Entity
#NoArgsConstructor
#Data
#AllArgsConstructor
public class Child implements Serializable {
#Id
private String name;
private String parentId;
#Valid
#Type(type = "json")
#Column(columnDefinition = "jsonb")
#ManyToOne(cascade = CascadeType.ALL)
#JoinColumn(name = "parentId", referencedColumnName = "id", insertable = false, updatable = false)
private Parent parent;
}
Parent Mapper
#Mapper
public interface ParentMapper {
#Mapping(target = "id", expression = "java(setId(parent.getName(), parent.getSsn()))")
ParentEntity toParentEntity(CreateParent parent);
Parent toParent(ParentEntity parentEntity);
default String setId(String name, String ssn) {
if (StringUtils.isNotEmpty(name) && StringUtils.isNotEmpty(ssn)) {
return String.format("%s+%s", name, ssn);
} else {
return null;
}
}
}
child mapper
#Mapper
public interface ChildMapper {
ChildEntity toChildEntity(CreateChild child, String parentId, String chaildName);
Child toChild(ChildEntity childEntity);
}
so there is an issue, creating and saving child object doesn't persist parent property of child object
Parent p = new Parent("somename","123456");
parentRepository.save(p);
Child c = new Child("somename");
c.setParentId(p.getId());
ChildEntity saved = childRepository.save(c);
saved.getParent() => returns null
ParentEntity savedParent = parentRepository.findById(p.getId());
savedParent.getChildren() => return null
Not sure what i done wrong ...

Spring Data JPA - ManyToOne unable to delete child without modifying parent list

I struggle for a week with the following problem:
How is it possible to delete a child entity through a repository without modifying the List on the owning (parent) side of the relation?
Thanks in advance.
I am hoping for some answers!
The child class:
#Entity
#Table(name = "child")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Child implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#ManyToOne
private Parent parent;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Long getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
And the parent class:
#Entity
#Table(name = "parent")
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Parent implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
#SequenceGenerator(name = "sequenceGenerator")
private Long id;
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Child> children = new HashSet<>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Set<Child> getChildren() {
return children;
}
public void setChildren(Set<Child> children) {
this.children = children;
}
public Parent addChild(Child child) {
this.children.add(child);
child.setParent(this);
return this;
}
public Parent removeChild(Child child) {
this.children.remove(child);
child.setParent(null);
return this;
}
}
And here the test:
#Test
#Transactional
public void testParentToChildRelationShip() {
Parent parent = new Parent();
Child child = new Child();
parent.addChild(child);
parent.addChild(new Child());
parent.addChild(new Child());
parent.addChild(new Child());
parentRepository.save(parent);
Assertions.assertThat(parentRepository.count()).isEqualTo(1L);
Assertions.assertThat(childRepository.count()).isEqualTo(4L);
childRepository.delete(child);
Assertions.assertThat(parentRepository.count()).isEqualTo(1L);
// fails
Assertions.assertThat(childRepository.count()).isEqualTo(3L);
parentRepository.delete(parent.getId());
Assertions.assertThat(parentRepository.count()).isEqualTo(0L);
Assertions.assertThat(childRepository.count()).isEqualTo(0L);
}
The test would work if I insert before deleting the child,
child.getParent().removeChild(child);
but I want to avoid calling this.
Is there a way to make it work with just calling the Child-JPA-Repository.delete method? Or other annotations that I missed?
Since child has association with parent you are facing this issue, you need to remove the link between child and parent either using
parent.removeChild(child);
or
child.getParent().removeChild(child);
Remove these lines from your parent class and also setter and getter of children
#OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
#JsonIgnore
#Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<Child> children = new HashSet<>();
I think you can remove child mapping from your parent class so you can easily delete the child row using ChildRepository delete() method but problem is that you have to save your child manually using ChildRepository save(). You can not save child object with parent object using ParentRepository. Change your Test code like below for saving child and parent
Parent parent = new Parent();
Parent parent = parentRepository.save(parent);
Child child = new Child();
child.setParent(parent);
childRepository.save(child);

MIssing parent reference in a bidirectional hibernate mapping

I have a spring rest backend with two entities with a bidirectional relationshop (one-to-many, many to one). To overcome nested fetching issues, #JsonManagedReference/#JsonBackReference has been used for a perent/child relationship between entities.
The entites look as this:
#Entity
#Table(name = "Parent")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Parent implements java.io.Serializable {
private Integer id;
private List<Child> childList;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
#JsonManagedReference
public List<Child> getChildList() {
return childList;
}
public void setChildListe(List<Child> childListe) {
this.childList = childList;
}
}
#Entity
#Table(name = "Child")
#JsonInclude(JsonInclude.Include.NON_NULL)
public class Child implements java.io.Serializable {
private Integer id;
private Parent parent;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "ID", unique = true, nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "ParentID")
#JsonBackReference
public Parent getParent() {
return parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
}
This works fine when fetching the Parent element, the childset is then fetched alongside and displayed as an json-array.
However, there is no reference to parent in the child element due to the usage of jsonbackreferance.
How can solve this issue ? I need parent reference when fetching child
That would lead to an infinite loop when serializing to JSON. That's the whole reason we don't do bi-direction JSON relationships.
What I would do is add an additional column to the child entity if you need the ID alone.
private Integer parentId;
#Column(name = "ParentID", insertable=false, updateable=false)
public Integer getParentId() {
return parentId;
}

jpaRepository findAll with parent and child use pagable

I'm using spring boot and jpa, I'm trying to get data from parent entity and child entity using jparepository.
Parent Entity:
#Entity
#Table(name = "parent")
public class Parent {
#Id
private int id;
private String name;
#OneToMany(mappedBy = "parent", fetch = FetchType.LAZY)
private Set<Child> children;
}
Child Entity:
#Entity
#Table(name = "child")
public class Child {
#Id
private int id;
private String name;
private int parent_id;
#ManyToOne
#JoinColumn(name = "parent_id", referencedColumnName = "id")
private Parent parent;
jpaRepository:
public interface ParentRepository extends JpaRepository<Parent, Integer>, JpaSpecificationExecutor<Parent> {
}
the reason I set the fecth to FetchType.LAZY is that sometimes I just want to get parent without child.
So, here is my question:
when I use
parentRepository.findAll(pagable);
the result only contains parents, not child, but I want the result to contain children, and in some situation I don't want it. how to write it ?
To fetch children collection you can declare an entity graph. Something like this:
#NamedEntityGraph(
name = "parent.withChildren",
attributeNodes = {
#NamedAttributeNode("children")
}
)
And then use it with repository methods:
#EntityGraph("parent.withChildren")
Page<Parent> findWithChidren(Pageable page);

Resources