我正在使用Spring Boot和Hibernate编写API,其中我的持久化实体对象也用作发送到客户端和从客户端发送的DTO。这是我使用的典型实体的简化版本:
@Entity
@Table(name = "STUDENT")
public class Student {
@Id
@GeneratedValue
@Column(name = "ID")
private Long id;
@ElementCollection
@CollectionTable(name = "GROUP_STUDENT",
joinColumns = @JoinColumn(name = "GROUP_ID"))
@Column(name="STUDENT_ID")
private Set<Long> groupIds;
@JsonIgnore
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="GROUP_STUDENT",
joinColumns = @JoinColumn(name="GROUP_ID"),
inverseJoinColumns = @JoinColumn(name="STUDENT_ID")
)
private Set<Group> groups = new HashSet<>();
// getters and setters
}
这是关联的类:
@Entity
@Table(name = "GROUP")
public class Group {
@Id
@GeneratedValue
@Column(name = "ID")
private Long id;
@JsonIgnore
@ManyToMany(fetch = FetchType.LAZY, mappedBy = "groups")
private Set<Student> students = new HashSet<>();
// getters and setters
}
如您所见,@ManyToMany
和Student
之间存在Group
关联。
由于我将这些对象发送到客户端,因此我选择仅发送关联的id而不是关联本身。我已使用this answer解决了这个问题,并且按预期工作。
问题是这个。当hibernate尝试持久化Student
对象时,它会按预期插入groups
,但它也会尝试将groupIds
插入到映射表GROUP_STUDENT
中。由于映射表复合id的唯一约束,这当然会失败。并且不可能将groupIds
标记为insertable = false
,因为它是@ElementCollection
。而且我不认为我可以使用@Formula
,因为我需要Set
而不是减值。
这当然可以通过在保存或持久保存这样一个实体之前总是清空groups
的{{1}}来解决,但这非常危险且容易忘记。
所以我想要的基本上是groupIds
类中的只读groupIds
,它从Student
映射表加载数据。这可能吗?我很感激任何建议,如果看起来不清楚,我很乐意就此提出问题。
答案 0 :(得分:1)
我设法通过制作id-collection @Transient
并使用@PostLoad
填充它来解决这个问题:
@Entity
@Table(name = "STUDENT")
public class Student {
@PostLoad
private void postLoad() {
groupIds = groups.stream().map(Group::getId).collect(Collectors.toSet());
}
@Id
@GeneratedValue
@Column(name = "ID")
private Long id;
@Transient
private Set<Long> groupIds;
@JsonIgnore
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(name="GROUP_STUDENT",
joinColumns = @JoinColumn(name="GROUP_ID"),
inverseJoinColumns = @JoinColumn(name="STUDENT_ID")
)
private Set<Group> groups = new HashSet<>();
// getters and setters
}