将@joinedColumn(table)属性设置为扩展另一个entiry类的实体类时的Hibernate异常

时间:2017-09-20 13:11:54

标签: java hibernate jpa

我有以下情况:

实体命令:

@Entity
public class Command {

@Id
@GeneratedValue
private long id;

@Column(nullable=false)
private Date timeOfExecution;

--constructors, getters, setters...--

扩展Command的实体CmdTest:

@Entity
@SecondaryTable(name = "CmdTest")
public class CmdTest extends Command{

    @Column(table = "CmdTest", nullable = false)
    private String testParam;

    @OneToOne
    @JoinColumn(table="CmdTest")
    private Citizen citizen;

    -- getters, setters, construcotr --
}

实体公民:

@Entity
public class Citizen {

    @Id
    @GeneratedValue
    private long id;

    @Column(nullable=false)
    private String name;

    @OneToOne(mappedBy="citizen")
    private CmdTest cmdTest;

    -- getters, setters, constructor --
}

正如您所看到的,我在Citizen和CmdTest之间存在双向关系。 我想首先坚持公民,然后是CmdTest。

我正在使用Web服务来调用MyBean的initTest()方法。 MyBean创建一个Citizen和一个CmdTest实例,然后尝试先保留公民,然后是CmdTest。

这是我的initTest()方法:

public void initTest() {

    CmdTest cmd = new CmdTest();
    cmd.setTestParam("asd");
    cmd.setTimeOfExecution(new Date());

    Citizen citizen = new Citizen();
    citizen.setName("John Doe");

    citizen.setCmdTest(cmd);
    cmd.setCitizen(citizen);

    em.persist(citizen);
    em.persist(cmd);

}

通过在公民字段上设置@JoinColumn(table =“CmdTest”)我尝试告诉JPA在C​​mdTest表中保留citizen_id外键,如果我注释掉该行,一切正常,但我在内部获得了citizen_id外键命令表。

当我把@JoinColumn(table =“CmdTest”)时,我得到以下异常:Not-null property references a transient value - transient instance must be saved before current operation

我知道我可以先坚持CmdTest将瞬态CmdTest对象放在持久化上下文中,然后是Citizen,它会起作用。我试过了。

但是,我想知道,为什么这不起作用?这是Hibernate或JPA中的错误吗?我似乎无法找到原因...

1 个答案:

答案 0 :(得分:0)

您遇到此异常是因为您尝试使用对citizen对象的引用来保存cmd对象,而您没有将cmd实例持久保存到数据库中。

hibernate如何工作,它持久化并管理数据库中的对象,当它试图保持citizen实例时,它发现它被映射到一个对象(cmd),当它试图在数据库中构建这种关系时,它将使用cmd查找相应的id对象,但它不会发现它无法找到它&#39 ;为什么你会得到例外Not-null property references a transient value - transient instance must be saved before current operation,因为cmd没有被保留。

在尝试保存persist/save对象之前,您需要cmd citizen对象到数据库,这就是您的代码应该如何:

public void initTest() {

    CmdTest cmd = new CmdTest();
    cmd.setTestParam("asd");
    cmd.setTimeOfExecution(new Date());

    Citizen citizen = new Citizen();
    citizen.setName("John Doe");

    em.persist(cmd);

    citizen.setCmdTest(cmd);
    cmd.setCitizen(citizen);

    em.persist(citizen);
}

所以这不是Hibernate中的错误,但这就是它的工作方式,您无法将对象映射到另一个transient(而不是{{ 1}})一个。