2009-10-07 109 views
11

我在我的数据模型中有两个名为User和UserProfile的实体。这是他们如何映射。从用户实体关于JPA级联的问题

代码:从用户配置实体

@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。但是当我尝试删除UserProfile实体时,相应的User实体仍然保留。 (当我尝试删除用户实体,相应的用户配置实体被删除。)

这里是我的问题: -

  • 做级联只能容纳当我拥有的关系,实体指定它们?
+2

你自己的证据会表明答案是“是” – skaffman 2009-10-07 22:38:47

+0

@skaffman .....所以,这是所有者和ownedBy概念背后的唯一原因吗?或者还有其他吗?谢谢。 – soontobeared 2009-10-07 23:02:23

回答

3

至于说

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

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

但是,你并没有提到它。也许你的UserProfile实体没有对用户实体的引用。

如JPA说明书所述

remove操作被级联到由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的书,您会看到以下

级联属性是有方向性的:它适用于只有一个下场协会

我认为这将是更好,因为

它适用于足协的只有一端每个操作

所以,你可以在同一把cascade属性在两侧时间,即使是双向关系。所以ChssPly是对的。

mappdeBy属性建立双向关系。 mappedBy属性将Address实体指定为关系的反面。这意味着客户实体是这种关系的主体。

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

+0

这是不正确的。首先,'mappedBy'与级联无关 - 它用来表示双向关系的非所有者一方。其次,“级联”属性是**属性**(如“不是关联”),因此它本身不是单向的或双向的。它可以应用于单向或双向关联(包括双方同时)。某些级联**类型**在非所有者协会方面可能没有意义。 – ChssPly76 2009-10-08 02:19:43

+0

谢谢你,ChssPly。由于我是非英语母语的人,因此在编写答案时我有一些限制。添加到原来的答案。 – 2009-10-08 05:02:16

+0

@Arthur - 感谢您的编辑(upvoting);我的意思并不是要苛刻或挑剔 - 只是想澄清一些观点。英语不是我的第一语言:-) – ChssPly76 2009-10-08 06:20:11

1

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

15

你的问题本身是错误的,这是所有混淆源于的地方。 Arthur的回答做得很好,但从评论中可以清楚地看出混乱仍然存在,所以让我在这里尝试一下。

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

“级联”是您在关系的一个(或双向)情况下指定的属性。它决定了什么动作上执行结束将传播到其他结束。在JPA中定义的动作有many different types,在Hibernate扩展中定义了even more。这种区别很重要 - 您应该只讨论特定的传播的行为,而不是一般的“级联”。

PERSIST,MERGE,REFRESH正常传播(从最后宣布到另一个)。

然而,REMOVE是棘手的,因为它可能意味着两个不同的东西。如果你有一个B之间的关系和你想删除一个,你可以删除在另一端,也可以删除该协会但留下完好。 Hibernate在两者之间做了明确的区分 - 您可以分别声明REMOVE(DELETE)和DELETE_ORPHAN级联类型; JPA规范没有。请注意,DELETE_ORPHAN不支持单值关系(OneToOne/ManyToOne)。因此,REMOVE的传播(单独或当它是ALL的一部分时)取决于关系是否具有明确的所有者(单向始终如此;如果使用mappedBy进行映射则双向执行并且如果它是映射通过连接表),在这种情况下,它从所有者传播到拥有者或没有所有者,在这种情况下,它向任一方向传播,但没有语义,除非它被明确指定。后者的典型例子是双向的多对多。

+0

嗨Chss,我已经尝试在这里,工作正常 - OneToOne和ManyToMany。虽然我使用Hibernate,但我认为它在JPA中的工作方式相同,因为hibernate是JPA的超集。我认为最好能否尽快显示代码,试图删除UserProfile及其引用的User实体。可能是应用程序抛出了约束违规,并且未删除引用的用户实体。假设它发生了什么,也很难。问候, – 2009-10-09 00:25:33

+0

...没有。 Hibernate是JPA的实现,这与“超集”无关 - 甚至没有任何意义 – specializt 2013-07-03 10:11:05

+1

如果您更新答案以反映当前JPA 2的孤儿行为,那将会很不错。 – 2013-07-10 16:38:14

0

使用JPA 2.x中,如果你想级联拆后使用orphanRemoval属性:

@OneToMany(orphanRemoval=true)

检查文档here获取更多信息。