Hibernate @ManyToMany 关系上的唯一约束冲突
Unique Constraint Violation on Hibernate @ManyToMany Relationship
我的数据库中有 3 个实体,我们称它们为 A
、B
和 C
。
A
和 B
彼此共享多对多关系。 A
有 B
的 SortedSet
,但 B
没有引用 A
(没有集合或配置 w/e)。所以我们有以下内容。
// Inside class A
@ManyToMany
@JoinTable(name = "a_b",
joinColumns = {@JoinColumn(name = "a_id")},
inverseJoinColumns = {@JoinColumn(name = "b_id")})
@LazyCollection(LazyCollectionOption.FALSE)
@SortNatural
private SortedSet<B> bSet = new TreeSet<B>();
B
和 C
之间存在一对多的关系(1 B
对许多 C
)。 C
在它的实体中有一个 B
,但 B
没有对它的许多 C
实体的引用。所以我们有以下
// Inside class C
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "b_id", nullable = false, updatable = true)
protected B b;
我们有一个同步进程,每晚运行一次作业,将 A
个实体及其关联更新为 B
个实体(不会经常更改)。我们最终得到类似于以下内容的结果(实际上,DAO、服务等要复杂得多)。
// Get the A value to be updated
A aToUpdate = entityManager.find(A.class, idForA);
// Out of scope of the question, but we need to figure out B via a string field on C
C cValue = myDao.getByProperty("fieldName", fieldValue);
// Determine the B values to set on aToUpdate
B bToSetOnA = cValue.getB();
TreeSet<B> bSet = new TreeSet<>();
bSet.add(bToSetOnA);
// Update aToUpdate
aToUpdate.setBSet(bSet);
aToUpdate = entityManager.merge(aToUpdate);
entityManager.flush();
发生这种情况时,会出现以下错误。
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (Sync Thread)
Duplicate entry 'myAId-almostMyBId' for key 'uk_a_b'
一件有趣的事是 almostMyBId
比实际的 B
ID 少 1 个字符。但只有完整的 ID 出现在 a_b table.
当我查看代码库时,a_b table 上的索引有一个 uk_a_b
约束。这是来自liquibase。
<createIndex indexName="uk_a_b" tableName="a_b" unique="true">
<column name="a_id"/>
<column name="b_id"/>
</createIndex>
如果删除 aToUpdate.setBSet(bSet);
行,错误就会消失。
我添加了日志记录并确认新 bSet
的 ID 与 aToUpdate
上的旧 ID 相同。
不知何故,Hibernate 似乎正在尝试重新添加关联,即使我们正在进行合并并且关联并没有真正改变。
我试过在这里和那里更改一些 CascadeType 和 FetchType 东西,但错误似乎并没有消失。有人知道发生了什么事吗?
这非常适合我的情况,但我想无论如何我都会 post 答案,以防有人阅读我的问题并一直在努力。
我团队中的另一位开发人员的任务是根据 a
和 a_b
table 加速报告。为避免需要执行 JOIN 和 WHERE 子句,开发人员将数据从 a_b
复制到新的 table 中(使用 WHERE 子句)并添加触发器,以便无论何时更新内容,它都会插入新的 table。这个新的 table 有一个与 a_b
table 同名的约束(即 uk_a_b
)。重复的案例没有得到妥善处理,因此引发了错误。由于名称相似,它似乎是 a_b
table 引起的问题,而实际上它是新的 table。娱乐时间。
我的数据库中有 3 个实体,我们称它们为 A
、B
和 C
。
A
和 B
彼此共享多对多关系。 A
有 B
的 SortedSet
,但 B
没有引用 A
(没有集合或配置 w/e)。所以我们有以下内容。
// Inside class A
@ManyToMany
@JoinTable(name = "a_b",
joinColumns = {@JoinColumn(name = "a_id")},
inverseJoinColumns = {@JoinColumn(name = "b_id")})
@LazyCollection(LazyCollectionOption.FALSE)
@SortNatural
private SortedSet<B> bSet = new TreeSet<B>();
B
和 C
之间存在一对多的关系(1 B
对许多 C
)。 C
在它的实体中有一个 B
,但 B
没有对它的许多 C
实体的引用。所以我们有以下
// Inside class C
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "b_id", nullable = false, updatable = true)
protected B b;
我们有一个同步进程,每晚运行一次作业,将 A
个实体及其关联更新为 B
个实体(不会经常更改)。我们最终得到类似于以下内容的结果(实际上,DAO、服务等要复杂得多)。
// Get the A value to be updated
A aToUpdate = entityManager.find(A.class, idForA);
// Out of scope of the question, but we need to figure out B via a string field on C
C cValue = myDao.getByProperty("fieldName", fieldValue);
// Determine the B values to set on aToUpdate
B bToSetOnA = cValue.getB();
TreeSet<B> bSet = new TreeSet<>();
bSet.add(bToSetOnA);
// Update aToUpdate
aToUpdate.setBSet(bSet);
aToUpdate = entityManager.merge(aToUpdate);
entityManager.flush();
发生这种情况时,会出现以下错误。
ERROR [org.hibernate.engine.jdbc.spi.SqlExceptionHelper] (Sync Thread)
Duplicate entry 'myAId-almostMyBId' for key 'uk_a_b'
一件有趣的事是 almostMyBId
比实际的 B
ID 少 1 个字符。但只有完整的 ID 出现在 a_b table.
当我查看代码库时,a_b table 上的索引有一个 uk_a_b
约束。这是来自liquibase。
<createIndex indexName="uk_a_b" tableName="a_b" unique="true">
<column name="a_id"/>
<column name="b_id"/>
</createIndex>
如果删除 aToUpdate.setBSet(bSet);
行,错误就会消失。
我添加了日志记录并确认新 bSet
的 ID 与 aToUpdate
上的旧 ID 相同。
不知何故,Hibernate 似乎正在尝试重新添加关联,即使我们正在进行合并并且关联并没有真正改变。
我试过在这里和那里更改一些 CascadeType 和 FetchType 东西,但错误似乎并没有消失。有人知道发生了什么事吗?
这非常适合我的情况,但我想无论如何我都会 post 答案,以防有人阅读我的问题并一直在努力。
我团队中的另一位开发人员的任务是根据 a
和 a_b
table 加速报告。为避免需要执行 JOIN 和 WHERE 子句,开发人员将数据从 a_b
复制到新的 table 中(使用 WHERE 子句)并添加触发器,以便无论何时更新内容,它都会插入新的 table。这个新的 table 有一个与 a_b
table 同名的约束(即 uk_a_b
)。重复的案例没有得到妥善处理,因此引发了错误。由于名称相似,它似乎是 a_b
table 引起的问题,而实际上它是新的 table。娱乐时间。