【问题标题】:Unique Constraint Violation on Hibernate @ManyToMany RelationshipHibernate @ManyToMany 关系的唯一约束违反
【发布时间】:2020-02-13 19:49:48
【问题描述】:

我的数据库中有 3 个实体,我们称它们为 ABC

AB 彼此共享多对多关系。 ASortedSetBs,但 B 不引用 A(没有收集或配置)。所以我们有以下内容。

// 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>();

BC 彼此之间存在一对多的关系(1 个B 到多个Cs)。 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 个字符。但是 a_b 表中只有完整的 ID。

当我查看代码库时,a_b 表的索引上有一个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 的东西,但错误似乎并没有消失。有人知道发生了什么吗?

【问题讨论】:

    标签: java hibernate persistence liquibase cascade


    【解决方案1】:

    这对我的情况非常具体,但我想无论如何我都会发布答案,以防有人阅读我的问题并一直在努力解决。

    我团队中的另一位开发人员的任务是加快基于 aa_b 表的报告。为了避免需要执行 JOIN 和 WHERE 子句,开发人员将数据从 a_b 复制到新表中(使用 WHERE 子句)并添加触发器,以便每当更新内容时,它都会插入到新表中。这个新表有一个与a_b 表相同的约束(即uk_a_b)。没有正确处理重复的情况,因此引发了错误。由于名称相似,它似乎是 a_b 表导致问题,而它实际上是新表。娱乐时间。

    【讨论】:

      猜你喜欢
      • 2016-09-27
      • 1970-01-01
      • 1970-01-01
      • 2020-04-01
      • 2020-05-28
      • 1970-01-01
      • 2012-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多