'JPA @OneToMany mapping inserting null values
I had a hard time with hibernate OneToMany mapping. I have googled to find the solution from morning nothing helped. Following are my code snippets.
package com.student.app.model;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import com.fasterxml.jackson.annotation.JsonProperty;
@Entity
@Table(name = "student")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "student_id")
private long id;
@Column(name = "student_name")
private String name;
@Column(name = "student_class")
@JsonProperty("class")
private String clazz;
@Column(name = "total_marks")
private int totalMarks;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "student")
private List<Subject> subjects;
public Student() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getClazz() {
return clazz;
}
public void setClazz(String clazz) {
this.clazz = clazz;
}
public int getTotalMarks() {
return totalMarks;
}
public void setTotalMarks(int totalMarks) {
this.totalMarks = totalMarks;
}
public List<Subject> getSubjects() {
return subjects;
}
public void setSubjects(List<Subject> subjects) {
this.subjects = subjects;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", clazz=" + clazz + ", totalMarks=" + totalMarks
+ ", subjects=" + subjects + "]";
}
}
Subject.java
package com.student.app.model;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;
@Entity
@Table(name = "subject")
public class Subject {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "subject_id")
private long id;
@Column(name = "subject_name")
private String name;
@Column(name = "marks")
private String marks;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "student_id")
private Student student;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMarks() {
return marks;
}
public void setMarks(String marks) {
this.marks = marks;
}
@Override
public String toString() {
return "Subject [id=" + id + ", name=" + name + ", marks=" + marks + "]";
}
}
StudentRepository.java
package com.student.app.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import com.student.app.model.Student;
@Repository
public interface StudentRepository extends JpaRepository<Student, Long> {
Student findStudentByName(String name);
}
POST Mapping
@PostMapping("/students")
public ResponseEntity<?> addStudent(@RequestBody Student student) {
try {
System.out.println("Student Object is : " + student);
Student studentData = studentRepository.save(student);
if (null == studentData) {
return ResponseEntity.noContent().build();
}
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{name}")
.buildAndExpand(studentData.getName()).toUri();
return new ResponseEntity<>(location, HttpStatus.CREATED);
} catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Post Request JSON
{
"name": "Vinod Kumar",
"class": "8th class",
"subjects": [
{
"name": "Telugu",
"marks": 85
},
{
"name": "English",
"marks": 80
},
{
"name": "Maths",
"marks": 90
}
],
"totalMarks": 580
}
Student Table data
STUDENT_ID STUDENT_CLASS STUDENT_NAME TOTAL_MARKS
1 8th class Vinod Kumar 580
Subject Table data
SUBJECT_ID MARKS SUBJECT_NAME STUDENT_ID
2 85 Telugu null
3 80 English null
4 90 Maths null
Here the issue is the STUDENT_ID column storing null values.
Solution 1:[1]
When you save a Student, Hibernate smart enough to insert a Student record to the database, get that record id and save all subjects of the Student with Subject.STUDENT_ID = generated student id, when the student and the subject connected to each other from both sides.
But by some reasons Hibernate doesn't connect a Subject with a Student as Java objects from the Subject side. It doesn't do for you
subject.setStudent(student)
This is the reason why Subject.STUDENT_ID = null in the database.
Before saving a student you have to assign the student to a subject for each subject, doing it in the loop
emptyStreamIfNull(student.getSubjects()).forEach(subject -> setStudent(student));
Some recommendations
Your database schema is not convenient. Student and Subject are tabular data.
So you need an additional object StudentSubjectMark.
Also use Long id for ids (not long id).
You have to log error here
catch (Exception e) {
e.printStackTrace();
return new ResponseEntity<>(HttpStatus.INTERNAL_SERVER_ERROR);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
