我如何保存一个包含实体的新学生,但不创建这些实体,因为它们已经存在于数据库中?
how do i save a new student that contains entities, but don't create these entities because they already exist in the database?
我想保存一名学生,一名学生有一个 TargetAudience 对象作为属性。这些目标受众已经硬编码在我的数据库中。 (目标受众 = 校园 + 专业)。现在当我 post 像这样时:
{
"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 不应该查看实体是否已经存在然后使用它吗?或者我怎样才能做到这一点?
抱歉,如果不清楚,这是我第一次 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;
}
您在尝试保存时遇到了什么异常?堆栈跟踪会更有帮助。但是,您可以通过两种方式解决此问题
或者,
如果你想完全避免保存 TargetAudience,你可以在 @Transient 注解中注解 TargetAudience 属性 这样,它就不会被考虑用于数据库保存。
或者,
JPA 正在尝试使用新的主键 every-time 保存对象,因为该对象处于分离状态(如果您的 JPA 提供程序是休眠的,这是默认的 JPA 提供程序)。您应该修改 StudentService 中的 registerStudent() 方法,例如 -
public Student registerStudent(Student student) {
TargetAudience targetAudience = targetAudienceRepository.findByMajorCode(student.getTargetAudience().getMajorCode());
student.setTargetAudience(targetAudience);
return student;
}
因此,您明确地从数据库中获取 TargetAudience 并将其设置为您正在获取的学生对象。这样,获取的 targetAudience 将处于持久状态(未分离),并且不会再次尝试分配新的主键。
我想保存一名学生,一名学生有一个 TargetAudience 对象作为属性。这些目标受众已经硬编码在我的数据库中。 (目标受众 = 校园 + 专业)。现在当我 post 像这样时:
{
"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 不应该查看实体是否已经存在然后使用它吗?或者我怎样才能做到这一点?
抱歉,如果不清楚,这是我第一次 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;
}
您在尝试保存时遇到了什么异常?堆栈跟踪会更有帮助。但是,您可以通过两种方式解决此问题
或者, 如果你想完全避免保存 TargetAudience,你可以在 @Transient 注解中注解 TargetAudience 属性 这样,它就不会被考虑用于数据库保存。
或者, JPA 正在尝试使用新的主键 every-time 保存对象,因为该对象处于分离状态(如果您的 JPA 提供程序是休眠的,这是默认的 JPA 提供程序)。您应该修改 StudentService 中的 registerStudent() 方法,例如 -
public Student registerStudent(Student student) {
TargetAudience targetAudience = targetAudienceRepository.findByMajorCode(student.getTargetAudience().getMajorCode());
student.setTargetAudience(targetAudience);
return student;
}
因此,您明确地从数据库中获取 TargetAudience 并将其设置为您正在获取的学生对象。这样,获取的 targetAudience 将处于持久状态(未分离),并且不会再次尝试分配新的主键。