I want to save a student and a student has a TargetAudience object as an attribute. These target audiences are allready hardcoded in my database. (targetaudience = campus + major). Now when i post like this:
{ "user": { "userName": "jan", "password": "tibo123", "role": "ROLE_STUDENT" }, "targetAudience": { "majorCode": "IW E-ICT", "campus": { "name": "GroepT", "street": "Andreas Vesaliusstraat", "postalCode": "3000", "streetNr": "13" } } }
it doesnt work because everythime it creates a new object for the campus and because i use name as a primary key it throws an exception. Shouldn’t spring data jpa look if the entity allready exists and then use that instead? Or how can i make it do this?
Sorry if this isn’t clear, it’s my first time posting
student.java:
package com.bachproject.demo.student; import com.bachproject.demo.onderwerp.Onderwerp; import com.bachproject.demo.targetAudience.TargetAudience; import com.bachproject.demo.user.User; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.*; import java.util.List; @Entity @Data @AllArgsConstructor @NoArgsConstructor public class Student { @Id @SequenceGenerator( name = "student_sequence", sequenceName = "student_sequence", allocationSize = 1 ) @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "student_sequence" ) private Long studentId; @OneToOne( cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = true ) @JoinColumn( name = "user_id", referencedColumnName = "userId" ) private User user; @OneToOne( cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = true ) @JoinColumn( name = "target_audience", referencedColumnName = "TargetAudienceId" ) private TargetAudience targetAudience; //private List<Onderwerp> preferences; }
StudentController.java
package com.bachproject.demo.student; import com.bachproject.demo.onderwerp.Onderwerp; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.List; @RestController @RequestMapping("/students") public class StudentController { @Autowired private StudentService studentService; @GetMapping @CrossOrigin(origins = "*") public List<Student> getStudents(){ return studentService.getStudents(); } @PostMapping("/register") @CrossOrigin(origins = "*") public Student registerStudent(@RequestBody Student student) { System.out.println(student); return studentService.registerStudent(student); } }
StudentService.java:
package com.bachproject.demo.student; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class StudentService { @Autowired private StudentRepository studentRepository; public List<Student> getStudents() { return studentRepository.findAll(); } public Student registerStudent(Student student) { return studentRepository.save(student); } }
TargetAudience.java:
package com.bachproject.demo.targetAudience; import com.bachproject.demo.campus.Campus; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.*; @Entity @Data @AllArgsConstructor @NoArgsConstructor public class TargetAudience { @Id @SequenceGenerator( name = "targetAudience_sequence", sequenceName = "targetAudience_sequence", allocationSize = 1 ) @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "targetAudience_sequence" ) private Long TargetAudienceId; // for example IW E-ICT-> industriele wetenschappen Elektronica ICT private String majorCode; @OneToOne( cascade = CascadeType.ALL, fetch = FetchType.EAGER, optional = true ) @JoinColumn( name = "campus", referencedColumnName = "name" ) private Campus campus; }
Campus.java:
package com.bachproject.demo.campus; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; import javax.persistence.Entity; import javax.persistence.Id; @Entity @Data @AllArgsConstructor @NoArgsConstructor public class Campus { @Id private String name; private String street; private String postalCode; private String streetNr; }
Advertisement
Answer
What exception are you facing while trying to save? A stack trace would’ve been more helpful. However, you can work around this in two ways
Either, If you want to avoid saving TargetAudience altogether, you can annotate the TargetAudience property in @Transient annotation so, it’ll not be considered for database saving.
Or, JPA is trying to save the object with new primary key every-time because the object is in detached state (if your JPA provider is hibernate, which is default JPA provider). You should modify registerStudent() method in StudentService like –
public Student registerStudent(Student student) { TargetAudience targetAudience = targetAudienceRepository.findByMajorCode(student.getTargetAudience().getMajorCode()); student.setTargetAudience(targetAudience); return student; }
So, you’re explicitly fetching TargetAudience from database and setting it to student object you’re getting. In this way, fetched targetAudience will be in persistent state (not detached) and it’ll not try to assign new primary key again.