gpt4 book ai didi

hibernate 3.6 : how to make use of deferred FK constraints when inserting entities with circular reference?

转载 作者:行者123 更新时间:2023-11-29 11:37:10 26 4
gpt4 key购买 nike

考虑以下在实体 A 和 B 中使用循环引用的 Hibernate 3.6 实体映射:

@MappedSuperclass
abstract class Entity {

@Id
protected UUID id = UUID.randomUUID();

@Version
protected Integer revision;
}

@Entity
class A extends Entity {
// not null in the database
@OneToOne(optional = false)
B b;
}

@Entity
class B extends Entity {
// not null in the database
@ManyToOne(optional = false)
A a;
}

实体的 id 是在创建新实例时生成的,因此它在任何 SQL INSERT 之前设置。要确定一个实例是否是 transient 的,可以使用 Interceptor:

class EntityInterceptor extends EmptyInterceptor {

@Override
public boolean isTransient(Object entity) {
return ((Entity)entity).getRevision == null;
}
}

当我尝试保存(在单个事务中)A 和 B 的实例(将引用设置为彼此)时,Hibernate 失败并出现 TransientObjectException(对象引用未保存的 transient 实例 - 保存刷新前的 transient 实例)。

A a = new A();
B b = new B();
a.setB(b);
b.setA(a);

// start transaction
sessionFactory.getCurrentSession().saveOrUpdate(a); // a before b or vice versa doesn't matter
sessionFactory.getCurrentSession().saveOrUpdate(b);
sessionFactory.getCurrentSession().flush();
// commit

当我将映射更改为 A.b 和 B.a 的级联保存时,Hibernate 会为 A 生成以下 SQL INSERT 语句:

INSERT INTO A (id, revision, b) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, NULL);

这违反了 A.b 上的 NOT NULL 约束并导致 ConstraintViolationException。即使 B 的 id 在插入时已知,它也没有在 SQL INSERT 中设置。在数据库 (PostgreSQL 9.1) 中,A.b 上的 FK 约束被定义为 DEFERRABLE INITIALLY DEFERRED,因此如果设置了 A.b,则以下 INSERT 语句将运行而不会出现任何错误:

START TRANSACTION;
INSERT INTO A (id, revision, b) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb');
INSERT INTO B (id, revision, a) VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 0, 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa');
COMMIT;

当我在数据库中删除 A.b 上的 NOT NULL 约束并保持 级联保存 映射上述代码以保存 A 和 B 时工作正常。编辑NOT NULL 约束在 PostgreSQL 中不能延迟,只有 FK 约束可以延迟。结束编辑老实说,我没有查看在这种情况下生成的 SQL 语句(我现在无法重现),但我想它看起来像这样:

START TRANSACTION;
INSERT INTO A (id, revision, b) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, NULL);
INSERT INTO B (id, revision, a) VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 0, 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa');
UPDATE A SET b = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb' WHERE id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa';
COMMIT;

我知道对于我在这里尝试做的事情可能有更好的实体设计,但我真的很想知道是否有办法保持 NOT NULL约束(如果可能的话还有没有级联保存的原始映射)并使我的原始代码工作。有没有办法告诉 Hibernate 只插入 A 且 A.b = B.id,即使 B 在插入 A 时是 transient 的?通常,我找不到任何有关 Hibernate 和延迟 FK 约束的文档,因此感谢任何关于此的指示。

最佳答案

你这里的都是经典bidirectional relationship .双方相互参照。如果你有双向的一侧需要标记为更强的一侧,这是通过使用 mappedBy 完成的。或反面标记灯芯侧。此外,您有 FK 约束,因此需要定义 not-null 为真,以便 hibernate 将使用 FK 插入。

看这个complete .

关于 hibernate 3.6 : how to make use of deferred FK constraints when inserting entities with circular reference?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11267089/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com