JPA 交叉单向 OneToOne
JPA cross unidirectional OneToOne
我有两个实体-classes A和B。对于A,只有一个class B的实例。通过应用程序的生命周期,我需要为A创建新的B实例. 但是对于历史记录日志,我需要存储 B 的先前实例以及指向此 A 实例的链接。所以我创建了下一个映射:
@Entity
class A {
@OneToOne
@JoinColumn(name="B_ID")
B b;
}
@Entity
class B {
@OneToOne
@JoinColumn(name="A_ID")
A a;
}
///////
CREATE TABLE A_TABLE (ID uuid, B_ID uuid, FOREIGN KEY (B_ID) REFERENCES B_TABLE(ID));
CREATE TABLE B_TABLE (ID uuid, A_ID uuid, FOREIGN KEY (A_ID) REFERENCES A_TABLE(ID));
我的表中已经有一些正确的数据,但是每次当我尝试获取 A class 的任何实例时,b 字段都是空的。那么,我做错了什么?
UPD_0
好的,这是我真正要处理的事情:
@MappedSuperclass
public abstract class BaseUuidEntity {
@Id
@Column(name = "ID")
@Persistent
protected UUID id;
}
@MappedSuperclass
public class StandartEntity extends BaseUuidEntity { ... }
@MappedSuperclass
public abstract class AbstractEntity extends BaseUuidEntity { ... }
@Entity(name = "CardEntity")
@Table(name = "TBL_CARD")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "CARD_TYPE", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("0")
public class CardEntity extends AbstractEntity { ... }
@Entity("aEntity")
@DiscriminatorValue("1")
@Table(name = "A_TABLE")
class A extends CardEntity {
@OneToOne
@JoinColumn(name="B_ID")
B b;
public String getBName() {
return b.getName(); // NullPointerException
}
}
@Entity("bEntity")
@Table(name = "B_TABLE")
class B extends StandartEntity {
@Column(name="name")
String name;
public String getName() {
return this.name;
}
}
-- A_TABLE (ID, B_ID)
'41a2647d-2ef6-f507-92ee-bff0f784b6f3', '5d3c66da-b377-11e4-bc9c-1008b124eacf'
-- B_TABLE (ID, A_TABLE, NAME)
'5d3c66da-b377-11e4-bc9c-1008b124eacf', '41a2647d-2ef6-f507-92ee-bff0f784b6f3', 'Some text'
我得到了所有 A 实体(在我的例子中 - 它是一个)
select e from aEntity e
并尝试在每个实体中获取 b 实体的名称,但得到空指针,导致 b 为空;
你需要 mappedBy 注释:http://en.wikibooks.org/wiki/Java_Persistence/OneToOne
通知 java 谁负责此关系以及何时存储“foreign”id。您还只需要一个实体中的外键,而不是两个!
我不确定它是否会有所不同,但请尝试更改 getBName()
中的代码以使用 getter 而不是直接引用实例变量 b
:
public String getBName() {
return getB().getName();
}
而不是:
public String getBName() {
return b.getName(); // NullPointerException
}
我怀疑这可能是问题所在,因为 JPA 实现为实体创建了代理,这些实体通常是您实体的子类,并且这些代理覆盖了您的 getter 和设置器。因此,如果您不使用 getter,则可能是实例变量未正确初始化。
我有两个实体-classes A和B。对于A,只有一个class B的实例。通过应用程序的生命周期,我需要为A创建新的B实例. 但是对于历史记录日志,我需要存储 B 的先前实例以及指向此 A 实例的链接。所以我创建了下一个映射:
@Entity
class A {
@OneToOne
@JoinColumn(name="B_ID")
B b;
}
@Entity
class B {
@OneToOne
@JoinColumn(name="A_ID")
A a;
}
///////
CREATE TABLE A_TABLE (ID uuid, B_ID uuid, FOREIGN KEY (B_ID) REFERENCES B_TABLE(ID));
CREATE TABLE B_TABLE (ID uuid, A_ID uuid, FOREIGN KEY (A_ID) REFERENCES A_TABLE(ID));
我的表中已经有一些正确的数据,但是每次当我尝试获取 A class 的任何实例时,b 字段都是空的。那么,我做错了什么?
UPD_0 好的,这是我真正要处理的事情:
@MappedSuperclass
public abstract class BaseUuidEntity {
@Id
@Column(name = "ID")
@Persistent
protected UUID id;
}
@MappedSuperclass
public class StandartEntity extends BaseUuidEntity { ... }
@MappedSuperclass
public abstract class AbstractEntity extends BaseUuidEntity { ... }
@Entity(name = "CardEntity")
@Table(name = "TBL_CARD")
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "CARD_TYPE", discriminatorType = DiscriminatorType.INTEGER)
@DiscriminatorValue("0")
public class CardEntity extends AbstractEntity { ... }
@Entity("aEntity")
@DiscriminatorValue("1")
@Table(name = "A_TABLE")
class A extends CardEntity {
@OneToOne
@JoinColumn(name="B_ID")
B b;
public String getBName() {
return b.getName(); // NullPointerException
}
}
@Entity("bEntity")
@Table(name = "B_TABLE")
class B extends StandartEntity {
@Column(name="name")
String name;
public String getName() {
return this.name;
}
}
-- A_TABLE (ID, B_ID)
'41a2647d-2ef6-f507-92ee-bff0f784b6f3', '5d3c66da-b377-11e4-bc9c-1008b124eacf'
-- B_TABLE (ID, A_TABLE, NAME)
'5d3c66da-b377-11e4-bc9c-1008b124eacf', '41a2647d-2ef6-f507-92ee-bff0f784b6f3', 'Some text'
我得到了所有 A 实体(在我的例子中 - 它是一个)
select e from aEntity e
并尝试在每个实体中获取 b 实体的名称,但得到空指针,导致 b 为空;
你需要 mappedBy 注释:http://en.wikibooks.org/wiki/Java_Persistence/OneToOne 通知 java 谁负责此关系以及何时存储“foreign”id。您还只需要一个实体中的外键,而不是两个!
我不确定它是否会有所不同,但请尝试更改 getBName()
中的代码以使用 getter 而不是直接引用实例变量 b
:
public String getBName() {
return getB().getName();
}
而不是:
public String getBName() {
return b.getName(); // NullPointerException
}
我怀疑这可能是问题所在,因为 JPA 实现为实体创建了代理,这些实体通常是您实体的子类,并且这些代理覆盖了您的 getter 和设置器。因此,如果您不使用 getter,则可能是实例变量未正确初始化。