我有一个问题,我试图隔离,我仍然不明白什么是错的。我有2个类(实体)->教师和学生和表的多对多关系(学生教师关系)与@EmbeddableId。
问题是,当我从数据库中检索教师的集合时,它不会检索与该教师链接的学生数据(多对多关系)。回到javax.persistence,它可以工作,但现在我使用jakax.persistence,它不能以这种方式工作,我想知道为什么。
至于依赖关系,我有Spring Web,Spring Data JPA,Lombok和PostgreSQL Driver
代码:
@Embeddable
@Data
public class StudentTeacherKey implements Serializable {
@Column(name = "teacher_id")
private UUID teacher_id;
@Column(name = "student_id")
private Long student_id;
}
x
@Entity
@Table(name = "STUDENT_TEACHER")
@Data
public class StudentTeacherRelation {
@JsonIgnore
@EmbeddedId
private StudentTeacherKey id;
@ManyToOne(fetch = FetchType.EAGER)
@MapsId("student_id")
@JoinColumn(name = "student_id")
private Student student;
@JsonIgnore
@ManyToOne(fetch = FetchType.EAGER)
@MapsId("teacher_id")
@JoinColumn(name = "teacher_id")
private Teacher teacher;
@Column(name = "extra_column")
private String extraColumn;
}
@Data
@Entity
@Table(name = "TEACHERS")
public class Teacher {
@Id
@Column(name = "teacher_id")
@GeneratedValue(strategy = GenerationType.UUID)
private UUID teacher_id;
@Column(name = "name")
private String name;
@OneToMany(mappedBy = "teacher", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<StudentTeacherRelation> students = new HashSet<>();
}
@Data
@Entity
@Table(name = "STUDENTS")
public class Student {
@Id
@Column(name = "student_id")
@GeneratedValue(strategy = GenerationType.AUTO)
private Long student_id;
@Column(name = "name")
private String name;
@JsonIgnore
@OneToMany(mappedBy = "student", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<StudentTeacherRelation> teacher = new HashSet<>();
}
的数据
public interface TeacherRepo extends JpaRepository<Teacher, UUID> {
}
public interface StudentRepo extends JpaRepository<Student, Long> {
}
的字符串
- 服务-
public interface TeacherService {
public Set<Teacher> getAllTeachers();
}
@Service
public class TeacherServiceImpl implements TeacherService{
private final TeacherRepo teacherRepo;
@Autowired
public TeacherServiceImpl(TeacherRepo teacherRepo) {
this.teacherRepo = teacherRepo;
}
@Override
public Set<Teacher> getAllTeachers() {
return new HashSet<>(teacherRepo.findAll());
}
}
- 控制器-
@RestController
@RequestMapping(path = "/teacher")
public class TeacherController {
private final TeacherService teacherService;
@Autowired
public TeacherController(TeacherService teacherService) {
this.teacherService = teacherService;
}
@GetMapping()
public Set<Teacher> getAllTeachers() {
return teacherService.getAllTeachers();
}
}
型
这是我得到的
[ {“教师_id”:“467 f4868 - 928 e-11 ee-b 9d 1 - 0242 ac 120002”,“姓名”:“教师”,“学生”:[] } ]
我应该把每个老师的学生也联系起来。
我更新了这个例子,以更清楚地说明为什么我需要这种方法->在连接表中有额外的列。
3条答案
按热度按时间esbemjvw1#
您所描述的方法是在Java中使用Spring和JPA处理多对多关系的常用方法。然而,有一些潜在的问题和改进需要考虑:
1.**延迟加载与急切加载:**在
Teacher
和Student
实体的@OneToMany
关系中使用FetchType.LAZY
是提高性能的标准做法。但是,这也意味着相关实体只有在代码中显式访问时才会加载。这可能是为什么在获取教师时不会检索到学生数据的原因。如果需要立即加载相关实体,可以切换到FetchType.EAGER
。但是,要小心急切加载,因为它可能会导致性能问题,特别是当您有大型数据集或复杂实体图时。1.**Jackson序列化和延迟加载:**在典型的Sping Boot 应用程序中,Jackson用于将实体序列化为JSON。使用延迟加载,Jackson在序列化这些实体时可能会遇到问题,因为延迟加载的集合在序列化时没有初始化。要解决此问题,您可以在序列化之前手动初始化这些集合,或者使用Hibernate的
@JsonIgnoreProperties
注解忽略它们。但是,更好的方法可能是使用数据传输对象(DTO)。DTO允许您通过网络选择性地发送所需的数据,避免与延迟加载相关的问题,并在内部数据模型和向用户公开的数据之间添加额外的抽象层。1.**使用DTO:**直接公开实体可能会导致几个问题,包括前面提到的延迟加载问题。DTO是一种模式,您可以专门为数据传输目的创建单独的类。这些类可以根据API使用者的确切数据要求进行定制,从而避免发送不必要的数据,并有助于将API层与数据库模型解耦。通过使用DTO,您可以手动将必要的数据加载到DTO中,从而有效地绕过与延迟加载和Jackson序列化相关的问题。
总结
总而言之,虽然延迟加载对性能有益,但它可能会使API中的序列化和数据检索复杂化。使用DTO提供了一种规避这些问题的方法,可以对通过API公开的数据进行更多控制,并可能提高应用程序的性能和可维护性。
nsc4cvqm2#
您的代码
在原始代码中,
Teacher
和Student
之间的多对多关系是通过中间实体StudentTeacherRelation
管理的。这种方法涉及一个复合键(StudentTeacherKey
)来处理关系。每个Teacher
和Student
实体都有一个StudentTeacherRelation
的Set
来表示关联。代码问题
***复杂性:**使用带有复合键的中间实体增加了关系管理的复杂性。
***延迟加载:**关系中的
LAZY
获取类型意味着除非显式访问,否则不会加载相关实体,导致数据检索问题。***数据检索:**似乎没有从数据库中检索到与教师关联的学生,可能是由于配置错误或延迟加载问题。
我的代码(在本文末尾)
重构后的代码在
Teacher
和Student
实体中使用了直接的@ManyToMany
注解,从而消除了对中间StudentTeacherRelation
实体的需要。我所做的更改
***直接多对多Map:**x1m15 n1x和x1m16 n1x两个实体都使用x1m13 n1x沿着x1m14 n1x,直接Map两个实体,简化关系。
***删除中间实体:**删除了
StudentTeacherRelation
实体和StudentTeacherKey
,降低了复杂性和潜在的错误来源。***transmitting Annotation:**在service方法中增加了
@Transactional(readOnly = true)
,保证transactions的正确处理,这对于实体的延迟加载尤为重要。为什么会有这些变化?
***简化:**在JPA中,直接的多对多Map是处理此类关系的一种更直接和传统的方式。它降低了复杂性并与标准实践保持一致。
***提高可读性和维护性:**删除中间实体和复合键,使代码更容易理解和维护。
***延迟加载问题的潜在解决方案:**通过重新构建关系并确保适当的事务边界,与延迟加载和数据检索相关的问题可能会得到解决。
摘要
重构后的代码旨在提供一种更干净、更易于维护、功能更强大的方法来管理Sping Boot 应用程序中的多对多关系。它简化了关系Map,并与常见的JPA实践保持一致,可能解决初始复杂设置中遇到的问题。
Teacher.java
字符串
Student.java
型
StudentRepo.java
型
TeacherRepo.java
型
TeacherService.java
型
TeacherServiceImpl.java
型
TeacherController.java
型
PS:
@Data
来自Lombokpbpqsu0x3#
你是自己创建关系表,并将它们设置为ManyToManyMap关系。整体Map是错误的-请参考-https://www.baeldung.com/jpa-many-to-many。按照示例,应该会有帮助。