无法使用JPA注释@OneToOne(cascade=CascadeType.ALL)



我有一个父类Contact,它与ContactType有一对一关系。

@OneToOne(cascade=CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

我正在尝试使用扩展JPARepository的ContactRepository.save((创建一个新联系人。我得到以下错误。

违反PRIMARY KEY约束类型。无法在对象ContactType 中插入重复的密钥

如果我将联系人类型声明更改为以下内容:

@OneToOne(cascade=CascadeType.MERGE, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

我得到以下错误:

对象引用未保存的瞬态实例-在刷新之前保存瞬态实例

用于创建联系人的代码(它只调用JPARepository.save(((:

contactsRepository.save(contact);

如何同时使用合并和持久化数据。

您提到的评论:

主键是字符串类型。如果用户在创建新联系人时输入新类型Ex:"Type2"。如果用户输入已存在的类型,则我不想插入新类型一行

这是有道理的,因此您会收到"无法插入重复密钥"错误。

事实上,联系人和联系人类型之间并没有一对一的关系,因为并不是每个联系人都有一个联系人类型。正如您所说,联系人类型是重复使用的。您应该在"联系人"one_answers"联系人类型"之间使用多对一,因为一个联系人只能有一个联系人类型,但一个联系人可以应用于多个联系人。同样的联系人类型可以是一个以上的联系人。

因此,您将其设置为多对一,然后在保存之前,您需要查找与给定联系人类型匹配的联系人类型,并插入该联系人类型(如果存在(,如果不存在,则填充该联系人类型,然后让级联保存新的联系人类型。

用调用contactsRepository.save(contact)

@OneToOne(cascade=CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

引发异常,因为持久性上下文级联persist操作,并将contactType视为具有主键集的transient,准备进行持久化。具有相同PK的行已经存在,因此出现错误。

第二种情况:

@OneToOne(cascade=CascadeType.MERGE, orphanRemoval = true)
@JoinColumn(name = "type")
private ContactType contactType;

操作是persist(而不是merge(,因此不级联。持久上下文将contactType视为transient,并且不能进一步使用persist,因为其中一个依赖项处于transient状态。

解决方案

摆脱级联:

@OneToOne
@JoinColumn(name = "type")
private ContactType contactType;

在调用contactsRepository.save(contact);之前,请确保contactType处于托管状态。你可以这样做:

contact.setContactType( entityManager.getReference(ContactType.class, contactType.getId()));

确保将getId()替换为主键getter。

contactTypecontact.setContactType(contactTypeRepository.merge(contactType));合并到持久性上下文中也是有效的。

最新更新