java 关于 JPA Cascading 的问题

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1534599/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-29 16:58:53  来源:igfitidea点击:

A question on JPA Cascading

javajpaannotations

提问by soontobeared

I have two entities called User and UserProfile in my datamodel. Here is how they are mapped.

我的数据模型中有两个名为 User 和 UserProfile 的实体。这是它们的映射方式。

Code from User Entity:

来自用户实体的代码:

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

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

Code from UserProfile Entity:

来自 UserProfile 实体的代码:

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

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

As you see, I have a cascadetype.all for the user attribute in UserProfile. But when I try deleting the UserProfile entity, the corresponding User entity still stays. (When I try deleting the User entity, corresponding UserProfile entity gets deleted.)

如您所见,我在 UserProfile 中有一个用于用户属性的级联类型.all。但是当我尝试删除 UserProfile 实体时,相应的 User 实体仍然存在。(当我尝试删除 User 实体时,相应的 UserProfile 实体被删除。)

Here is my question:-

这是我的问题:-

  • Do cascades hold only when I specify them on the entity owning the relationship ?
  • 只有当我在拥有关系的实体上指定级联时,级联才成立吗?

回答by ChssPly76

Your question is wrong in and of itself, which is where all the confusion stems from. Arthur did a good job with his answer but it's clear from the comments the the confusion still remains so let me take a stab at it here.

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

Do cascades hold only when I specify them on the entity owning the relationship?

只有当我在拥有关系的实体上指定级联时,级联才成立吗?

"cascade" is an attribute you specify on one (or possibly both in case of bi-directional) end of a relationship. It determines what actionsperformed on thatend will be propagated to the otherend. There are many different typesof those actions defined in JPA and even moredefined in Hibernate extensions. This distinction is important - you should only talk about specificbehavior being propagated and not "cascade" in general.

“级联”是您在关系的一端(或在双向的情况下可能是两者)指定的属性。它确定在端执行的哪些操作将传播到另一端。有许多不同类型的JPA定义,这些行动在Hibernate的扩展定义。这种区别很重要 - 您应该只谈论正在传播的特定行为,而不是一般的“级联”。

PERSIST, MERGE, REFRESH propagate normally (from the end they were declared on to the other).

PERSIST、MERGE、REFRESH 正常传播(从最后它们被声明到另一个)。

REMOVE, however, is tricky because it can mean two different things. If you have a relationship between Aand Band you're trying to remove A, you can either remove Bon the other end OR you can remove the associationbut leave Bintact. Hibernate makes a clear distinction between the two - you can declare REMOVE (DELETE) and DELETE_ORPHANcascade types separately; JPA spec does not. Note that DELETE_ORPHANis not supported to single-valued relationships (OneToOne / ManyToOne).

然而,REMOVE 很棘手,因为它可能意味着两件事。如果您在AB之间存在关系并且您试图删除A,则可以删除另一端的B或者您可以删除关联但保留B不变。Hibernate 明确区分了两者——您可以分别声明 REMOVE (DELETE) 和DELETE_ORPHAN级联类型;JPA 规范没有。请注意,DELETE_ORPHAN不支持单值关系(OneToOne / ManyToOne)。

Thus, propagation of REMOVE (by itself or when it's part of ALL) depends on whether relationship has a clear owner (uni-directional always does; bi-directional does if it's mapped using mappedByand does not if it's mapped via join table) in which case it's propagated from owner to owned OR no owner in which case it's propagated in either direction but without DELETE_ORPHANsemantics unless it was explicitly specified. Typical example of the latter is bi-directional many-to-many.

因此,REMOVE 的传播(单独或当它是 ALL 的一部分时)取决于关系是否有明确的所有者(单向总是如此;如果使用mappingBy映射,则双向是这样,如果通过连接表映射则不是)在这种情况下,它从所有者传播到拥有者或没有所有者,在这种情况下,它会向任一方向传播,但没有DELETE_ORPHAN语义,除非明确指定。后者的典型例子是双向多对多。

回答by Arthur Ronald

As said

正如所说

When i try deleting the UserProfile entity, the corresponding User entity still stays

当我尝试删除 UserProfile 实体时,相应的 User 实体仍然存在

Maybe when you try to remove a UserProfile you get an integrity constraint violation from the database - do you use MyISAM engine in MySQL ?

也许当您尝试删除 UserProfile 时,您会从数据库中获得完整性约束违规 - 您是否在 MySQL 中使用 MyISAM 引擎?

But as you does not says nothing about it. Maybe your UserProfile entity does not have a reference to a User entity.

但正如你并没有说什么。也许您的 UserProfile 实体没有对 User 实体的引用。

As said in JPA specification

正如 JPA 规范中所说

remove operation is cascaded to entities referenced by X, if the relationship from X to these other entities is annotated with the cascade=REMOVE or cascade=ALL annotation element value

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

Something like

就像是

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();

Or you have something like

或者你有类似的东西

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();

In response to ChhsPly's comment:

回应 ChhsPly 的评论:

In Java Persistence with Hibernate book, you see the following

在 Java Persistence with Hibernate 一书中,您会看到以下内容

The cascade attribute is directional: It applies to only one end of the association.

级联属性是有方向的:它仅适用于关联的一端

I think it would be better as

我认为它会更好

It applies to only one end of the association per operation

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

So you can put cascade attribute in both sides at the same time, even in a bidirectional relationship. So ChssPly is right.

所以你可以同时在两边放置级联属性,即使是双向关系。所以 ChssPly 是对的。

mappdeBy attribute sets up the bidirectional relationship. mappedBy attribute designated the Address entity as the inverse side of the relationship. This means that the Customer entity is the owning side of the relationship.

mappdeBy 属性设置双向关系。mappingBy 属性将 Address 实体指定为关系的反面。这意味着 Customer 实体是关系的拥有方。

ChssPly is right when he says mappedBy has nothing to do with cascading

ChssPly 说的对,mappedBy 与级联无关

回答by non sequitor

That is correct when you have a bi-directional relationship the owner dictates the cascade rules since it is the "owner". The "owned" entity essentially follows orders, it can't give the orders -- so to speak.

当您有双向关系时,这是正确的,所有者决定级联规则,因为它是“所有者”。“拥有”实体本质上遵循命令,它不能发出命令——可以这么说。

回答by Mifmif

With JPA 2.x , if you want a cascade remove then use orphanRemovalattribute :

使用 JPA 2.x ,如果您想要级联删除,请使用 orphanRemoval属性:

@OneToMany(orphanRemoval=true)

@OneToMany(orphanRemoval=true)

check documentation herefor more info.

在此处查看文档以获取更多信息。