我有一个 @OneToMany 关系,其中 @Many 端在数据库中必须是唯一的。每当我尝试使用现有的 @Many 实体持久化 @One 实体时,冬眠都会尝试再次持久化 @Many 一侧,并中断数据库完整性。我需要自动检查 @Many 端是否存在,如果存在,则仅链接两个实体。
考虑一个 Studio 对象,该对象可以具有许多 Tag 对象。每个 Tag 在数据库中都是唯一的,并且可以链接到许多 Studio (以及其他实体)。 Tag 仅链接到给定的 Studio 一次。当前,如果我使用相同的 Tag 坚持使用2个不同的 Studio ,则 Tag 会两次插入数据库,这会破坏其完整性。如何设计关系以确保 @Many 端的唯一性?我可以在DAO层中手动检查它,但我希望休眠状态可以解决它(有很多与Tag相似的属性,手动执行检查会使代码难以读/写)
我有5个共享相似属性的实体,这些实体归为一个共同的父对象:
public abstract class AbstractMovieEntity<T extends AbstractMovieEntity> {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
protected Long id;
@NonNull
@Column(unique = true, nullable = false)
protected String name;
@EqualsAndHashCode.Exclude
@OneToMany(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
protected Set<EntityTag> tags = new HashSet<>();
...
工作室是以上内容的专业化
@EqualsAndHashCode(callSuper=true)
@Getter
@Setter
@Entity
@NoArgsConstructor
public class Studio extends AbstractMovieEntity<Studio> {
...
}
我写了一个模拟实际应用的测试
@Autowired
private EntityManager entityManager;
@Test
public void studioTagsAreNotDuplicated() {
Studio warners = new Studio("Warner Bros.");
warners.addTag("Great Movies");
Studio marvel = new Studio("Marvel");
marvel.addTag("Great Movies");
entityManager.persist(warners);
entityManager.persist(marvel); // <-- ConstraintViolationException
...
}
以上结果导致ConstraintViolationException,因为第二个entityManager.persist调用尝试再次保留Tag。如果我尝试将entityManager.persist更改为entityManager.merge,则会遇到相同的问题。我能正确表示这种关系吗?我希望休眠在尝试插入之前检查标记是否存在,然后链接数据库中的两个实体。
这些表的定义如下:
CREATE TABLE STUDIO (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
name varchar(255) not null,
description varchar,
master_id BIGINT REFERENCES STUDIO(id),
image_collection_id BIGINT REFERENCES IMAGE_COLLECTION(id)
);
CREATE TABLE ENTITY_TAG (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
tag varchar(255) not null UNIQUE
);
CREATE TABLE STUDIO_TAGS (
studio_id BIGINT REFERENCES STUDIO(id),
tags_id BIGINT REFERENCES ENTITY_TAG(id)
);
感谢您的帮助