在JPA级联的一个问题(A question on JPA Cascading)

2019-08-17 11:45发布

我有两个实体称为用户和用户配置在我的数据模型。 这里是他们是如何映射。

从用户实体代码:

@OneToOne(cascade=CascadeType.ALL)
@PrimaryKeyJoinColumn
public UserProfile getUserProfile(){
    return this.userProfile;
}

public void setUserProfile(UserProfile userProfile){
    this.userProfile=userProfile;
}

代码用户配置实体:

@OneToOne(mappedBy="userProfile",cascade=CascadeType.ALL)
public User getUser(){
    return this.user;
}

public void setUser(User user){
    this.user=user;
}

正如你看到的,我有一个在用户配置用户属性的cascadetype.all。 但是,当我尝试删除用户配置实体,相应的用户实体仍然停留。 (当我尝试删除用户实体,相应的用户配置实体被删除。)

这里是我的问题: -

  • 做级联持有,只有当我在拥有关系的实体指定它们?

Answer 1:

你的问题是错误的本身,这是所有的混乱源于。 亚瑟与他的回答一个很好的工作,但它是从评论的混乱仍然存在,所以让我花刺在这里清楚。

做级联持有,只有当我在拥有关系的实体指定它们?

“级联”是你(在双向的情况下,或可能两者)的关系的端部上的一个指定的属性。 它决定了最终执行的操作将传播到另一端。 有许多不同类型的JPA定义,这些行动更在Hibernate的扩展定义。 这种区别很重要-你应该只说说具体行为一般被传播,而不是“级联”。

PERSIST,MERGE REFRESH传播通常(从它们被宣布到其他的端部)。

REMOVE,然而,是棘手,因为它可能意味着两个不同的东西。 如果你有AB之间的关系,你想删除 ,你可以删除在另一端B或可以解除关联 ,但留下完好无损。 Hibernate会在两者之间有明显的区别-你可以声明删除(删除)和DELETE_ORPHAN分别级联类型; JPA规范没有。 需要注意的是DELETE_ORPHAN不支持对单值关系(OneToOne /多对一)。

因此,REMOVE的传播(由本身或当它的所有的一部分)取决于关系是否有明确的所有者(单向总是如此;如果它使用的mappedBy映射,如果它映射不经由连接表双向一样)在这种情况下,它是从拥有者拥有或没有所有者,在这种情况下,它在任何一个方向,但没有传播传播DELETE_ORPHAN语义,除非被明确指定。 后者的典型例子是双向多到许多。



Answer 2:

至于说

当我尝试删除用户配置实体,相应的用户实体仍然停留

也许当你尝试删除你的完整性约束违规从数据库中用户配置 - 你使用MyISAM引擎在MySQL?

但是当你不说一无所知。 也许你的用户配置实体没有一个用户实体的引用。

如在JPA规范说

除去操作级联到由X引用的实体 ,如果从X到这些其他实体的关系被注释与级联= REMOVE或级联= ALL注释元素值

就像是

UserProfile up = entityManager.find(UserProfile.class, id);

entityManager.close();

// Notice User is null outside a persistence context 
// So user will be not removed from the database because UserProfile does not have a reference to it
up.setUser(null);

entityManager.getTransaction().begin();

entityManager.remove(up);

entityManager.getTransaction().commit();

或者你有什么样

entityManager.getTransaction().begin();

UserProfile up = entityManager.find(UserProfile.class, id);

// throws UPDATE USER_PROFILE SET USER_ID = NULL
up.setUser(null);

// up.getUser() is null
// So user is not removed
entityManager.remove(up);

entityManager.getTransaction().commit();

为了响应ChhsPly的评论:

在Java持久性与Hibernate的书,您会看到以下

级联属性是有方向性的: 它仅适用于一个协会的结束

我认为这将是更好的

它适用于每个操作的关联仅一端

所以,你可以在同一时间放于两侧级联属性,即使是在一个双向的关系。 所以ChssPly是正确的。

mappdeBy属性设置双向关系 。 的mappedBy属性指定的地址实体的关系的逆侧。 这意味着客户的实体是关系的拥有方。

ChssPly是正确的,他说的mappedBy无关与级联



Answer 3:

这是正确的,当你有一个双向关系的所有者决定了级联规则,因为它是“老板”。 在“拥有”实体基本上遵循的订单,它不能给订单 - 可以这么说。



Answer 4:

随着JPA 2.x中,如果你想级联删除,然后使用orphanRemoval属性:

@OneToMany(orphanRemoval=true)

检查文档在这里获取更多信息。



文章来源: A question on JPA Cascading