我如何保存一个包含实体的新学生,但是没有创建这些实体,因为它们已经存在于数据库中?
我想保存一个学生,并且学生有一个 TargetAudience 对象作为属性。这些目标受众都已硬编码在我的数据库中。 (目标受众=校园+专业)。现在,当我像这样发布时:
{
"user": {
"userName": "jan",
"password": "tibo123",
"role": "ROLE_STUDENT"
},
"targetAudience": {
"majorCode": "IW E-ICT",
"campus": {
"name": "GroepT",
"street": "Andreas Vesaliusstraat",
"postalCode": "3000",
"streetNr": "13"
}
}
}
它不起作用,因为它每次都会为校园创建一个新对象,并且因为我使用名称作为主键,所以它会抛出异常。 spring data jpa 不应该查看实体是否已经存在然后使用它吗?或者我怎样才能让它做到这一点?
抱歉,如果不清楚,这是我第一次发布
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;
}
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您在尝试保存时遇到什么异常?堆栈跟踪会更有帮助。但是,您可以通过两种方式解决这个问题
,
如果您想完全避免保存 TargetAudience,可以在 @Transient 注释中注释 TargetAudience 属性,这样就不会考虑将其用于数据库保存。
或者,
JPA 每次都尝试使用新的主键保存对象,因为该对象处于分离状态(如果您的 JPA 提供程序是 hibernate,这是默认的 JPA 提供程序)。您应该修改 StudentService 中的 registerStudent() 方法,例如 -
因此,您显式从数据库中获取 TargetAudience 并将其设置为您获得的学生对象。这样,获取的 targetAudience 将处于持久状态(未分离),并且不会再次尝试分配新的主键。
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 -
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.