Hibernate异常:分离的实体传递给persist,在单向ManyoOne关系中

时间:2017-10-15 00:42:56

标签: spring hibernate spring-mvc jpa spring-data-jpa

我是Hibernate的新手,我遇到了经典的"分离的实体,它被传递给了#34;例外。我在这里读了几个类似的问题,但不适用于我的情况。
我有2个实体,Department和DeptEmpCode。 Department有一个引用DeptEmpCode的外键。许多部门可能共享一个代码,因此它是多对一的 实体代码如下:
部:

@Entity
@Table(name = "department")
public class Department {
    private Integer id;
    ...
    private DeptEmpCode status;
    ...
    @ManyToOne(cascade=CascadeType.ALL)
    @JoinColumn(name = "status")
    public DeptEmpCode getStatus() {
        return status;
    }
    public void setStatus(DeptEmpCode status) {
        this.status = status;
    }
}

DeptEmpCode:

@Entity
@Table(name = "code")
public class DeptEmpCode {
    private Integer id;
    ....
}

我省略了不必要的代码以便于阅读 所以,当我点击"添加部门"在网页上的按钮,spring框架为我创建了一个Department对象。然后我使用" new"创建DeptEmpCode对象,并调用Department的setStatus()将DeptEmpCode对象与Department关联。然后我坚持部门。代码如下:

public void saveDept(Department dept) {
    if(dept.getStatus() == null){
        DeptEmpCode status = new DeptEmpCode(); 
        status.setId(Constants.DEFAUL_DEPT_STATUS_ID);
        dept.setStatus(status);
    }
    deptDAO.save(dept); //nothing but a persist() call
}

那么问题应该是什么?我应该双向还是别的?(如果我删除" cascadeType.ALL"那么它将是外键违规)。谢谢!

1 个答案:

答案 0 :(得分:1)

因为已经创建了Department对象。使用cascadeType.MERGE代替cascadeType.ALL

当你使用cascadeType.ALL时,它会认为该事务是PERSISTED,它也会尝试PERSIST部门,因为部门已经在数据库中,所以它不起作用。但是使用CascadeType.MERGE,部门会自动合并(更新)。

<强>更新 服务

@Override
@Transactional
public void saveDept(Department dept) {
    if(dept.getStatus() == null){
        DeptEmpCode status = new DeptEmpCode();
        status.setId(Constants.DEFAUL_DEPT_STATUS_ID);
        status.setType("DEFAULT");
        status.setValue("DEFAULT");
        dept.setStatus(status);
    }
    deptDAO.update(dept);
}

DAO

@Override
public void update(Department dept) {
    em.merge(dept);
}

说明: 因为status.id是主键,您可以自己设置值。当你调用save时它将首先创建状态,这意味着状态已经(分离对象)注册在数据库中(尚未提交),如果你仍然使用em.persist(dept),它也会尝试持久化分离对象(状态)和部门。所以我们应该使用merge来合并状态并插入一个新的部门。 你可以在下面看到hibernate如何插入你的记录。

但是,如果您没有设置status.id值并让它自动生成,那么它将同时保持部门和状态。所以你不会遇到问题。在您的情况下,我知道您要将status.id分配给默认值为1。所以你应该使用merge,因为你将拥有使用默认状态id的第二和第三部门(状态ID已经在db中)。

Hibernate: insert into code (DES, INACTIVE_IND, CODE_TYPE, VALUE) values (?, ?, ?, ?)
Hibernate: insert into department (contact, des, dept_email, dept_name, status) values (?, ?, ?, ?, ?)