【问题标题】:Not able to use JPA annotation @OneToOne(cascade=CascadeType.ALL)无法使用 JPA 注释 @OneToOne(cascade=CascadeType.ALL)
【发布时间】:2018-11-20 20:05:20
【问题描述】:

我有一个父类 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);

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

【问题讨论】:

  • 有多少种联系方式?请张贴联系人类型的代码?
  • Contact Type 只是一个指向 Type 表的简单类。它可以有与插入一样多的行值。
  • 什么是主键?你的意思是有多少行就有多少联系人?
  • 主键是字符串类型。如果用户在创建新联系人时输入新类型 Ex:"Type2",它应该在类型表中插入一个新行。如果用户输入已经存在的类型,那么它应该插入一个新行。

标签: java sql spring-boot sql-server-2012 spring-data-jpa


【解决方案1】:

您提到的 cmets:

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

这是有道理的,那么为什么您会收到无法插入重复键错误。

现实情况是,联系人和联系人类型之间没有一对一的关系,因为每个联系人都没有一个联系人类型。正如您所说,联系人类型被重用。您应该做的是在联系人和联系人类型之间使用多对一,因为一个联系人只能有一种联系人类型,但一种联系人类型可以应用于多个联系人。 Iow,相同的联系人类型可以是多一个联系人。

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

【讨论】:

  • 给定的联系人只能有一种类型。它不能有多个与之关联的值。例如:类型表有 2 行 type1 和 type2。 Contact1 只能有 type1 或 type2 中的一个。如果用户输入 type3 那么它应该创建一个新的行 type3。
【解决方案2】:

致电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)); 合并到持久化上下文中也是有效的。

【讨论】:

  • 我可以添加行,但子表 (Contc_id) 中的外键 ID 输入为 Null。它没有输入新生成的联系人ID。
猜你喜欢
  • 1970-01-01
  • 2013-08-20
  • 1970-01-01
  • 2012-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-25
  • 1970-01-01
相关资源
最近更新 更多