我有两个实体: A 和 B 。 B 使用与 A 实体相同的PK。 A 和 B 与 one-2-one ,可选 = false assosiation相关联。
我做了什么:
//in session scope
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
session.save(a);
session.flush(); //EXCEPTION!
例外:
org.postgresql.util.PSQLException:错误:表“B”上的插入或更新违反了外键约束“fk_A_pk” 细节:表“A”中没有键(id)=(5600)
出了什么问题:
由于 PS3 ,我无法使用null B 属性保存 A ,因为关系是强制性的。但我不能 使用非null属性保存 A ,因为 A 还没有aID, B 无法想象自己的ID。
问题:
我怎样才能保存 A& B 实体?
PS1 B.PK同时是FK到A.PK字段。
PS2 从生成的sql ,我看到Hibernate在继续'插入A''插入B ...'查询>。
PS3
A class:
@Entity
@Table(name = "A")
@Inheritance(strategy= InheritanceType.JOINED)
public class A{
@Id
@SequenceGenerator(name = "a_sequence", sequenceName = "sq_a")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "a_sequence")
@Column(name = "id")
private long aID;
@JsonIgnore
@OneToOne(mappedBy="a", cascade = CascadeType.ALL, optional = false, fetch = FetchType.LAZY)
private B b;
}
B class:
@Entity
@Table(name="b")
public class B {
@Id
@Column(name="id", unique=true, nullable=false)
@GeneratedValue(generator="gen")
@GenericGenerator(name="gen", strategy="foreign", parameters=@Parameter(name="property", value="a"))
private long aID;
@JsonIgnore
@PrimaryKeyJoinColumn
@OneToOne(cascade = CascadeType.ALL)
private A a;
}
ADDITION(PostgreSQL DDL):
CREATE TABLE A
(
id bigint NOT NULL,
CONSTRAINT pk_file PRIMARY KEY (id )
)
CREATE TABLE B
(
id integer NOT NULL,
CONSTRAINT pk_file PRIMARY KEY (id ),
CONSTRAINT fk_a_pk FOREIGN KEY (id)
REFERENCES A (id) MATCH SIMPLE
ON UPDATE NO ACTION ON DELETE NO ACTION
)
答案 0 :(得分:1)
optional = false
上的 tl; dr:A
告诉Hibernate首先插入B
。
使关联单向
JPA JavaDoc提供了one-to-one association that assumes both the source and target share the same primary key values的示例,但它使用了单向关联:
从A
删除关联:
@Entity
public class A {
@Id
@SequenceGenerator(...)
@GeneratedValue(...)
private long aId;
}
如果您使用的是支持JPA 2.0的Hibernate版本(最新版本),请在@MapsId
上指定B
属性,删除外部生成器:
@Entity
public class B {
@Id
private long aId;
@OneToOne
@MapsId
private A a;
}
保持协会双向
您无法将optional = false
放在@OneToOne
中的A
注释中。由于引用B.id
的外键(A
)是必需的,因此您应首先插入A
:
INSERT INTO A (id) VALUES (1);
-- there isn't a corresponding record in B,
-- until we perform a second insert into B:
INSERT INTO B (id) VALUES (1);
知道这一点,让我们再次双向关联:
@Entity
public class A {
@Id
@SequenceGenerator(...)
@GeneratedValue(...)
private long aId;
// should work without 'optional = false'
@OneToOne(mappedBy = "a", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private B b;
}