JPA中级联(casecade)与关联关系的方向有关吗?

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

from http://stackoverflow.com/questions/1534599/a-question-on-jpa-cascading

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

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:

@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.)

Here is my question:-

  • Do cascades hold only when I specify them on the entity owning the relationship ?
link | improve this question

62% accept rate
 
1  
your own evidence would suggest that the answer is "yes" –  skaffman  Oct 7 '09 at 22:38
 
@skaffman.....So, is this the only reason behind the concept of owner and ownedBy? Or are there any other? Thanks. –  soontobeared  Oct 7 '09 at 23:02
feedback

3 Answers

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 actions performed on that end will be propagated to the other end. There are many different types of those actions defined in JPA and even more defined in Hibernate extensions. This distinction is important - you should only talk about specific behavior being propagated and not "cascade" in general.

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

REMOVE, however, is tricky because it can mean two different things. If you have a relationship betweenA and B and you're trying to remove A, you can either remove B on the other end OR you can remove the association but leave B intact. Hibernate makes a clear distinction between the two - you can declare REMOVE (DELETE) and DELETE_ORPHAN cascade types separately; JPA spec does not. Note that DELETE_ORPHAN is not supported to single-valued relationships (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 mappedBy and 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_ORPHAN semantics unless it was explicitly specified. Typical example of the latter is bi-directional many-to-many.

link | improve this answer
 
Hi Chss, i have tried here and works fine - OneToOne and ManyToMany. Although i have used Hibernate i think it works same way in JPA because hibernate is a superset of the JPA. I think it would be better whether soontobeared had showed the code where he try to remove UserProfile and its referenced User entity. Maybe a constraint violation is thrown by the application and the referenced User entity is not removed. Again it is difficult suppose what it happened. regards, –  Arthur Ronald F D Garcia  Oct 9 '09 at 0:25
feedback

As said

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

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

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

As said in JPA specification

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

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:

In Java Persistence with Hibernate book, you see the following

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.

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.

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

link | improve this answer
 
That is incorrect. First of all, mappedBy has nothing to do with cascading - it's used to signify the non-owner side of bi-directional relationship. Secondly, "cascade" attribute is an attribute (as in "not an association") so it's not unidirectional or bi-directional in itself. It can be applied to either uni-directional or bi-directional association (including both sides simultaneously). Certain cascade types may not make sense on non-owner association side. –  ChssPly76  Oct 8 '09 at 2:19
 
Thank you, ChssPly. As i am a non-native english speaker, i have some limitations when writing some answer. Added to original answer. –  Arthur Ronald F D Garcia  Oct 8 '09 at 5:02
 
@Arthur - thanks for your edits (upvoting); I didn't mean to be harsh or nitpick at phrasing - just wanted to clarify some points. English isn't my first language either :-) –  ChssPly76  Oct 8 '09 at 6:20
 
@Arthur..I am confused...I tested it again,but its still the same. I tested it with a bidirectional many-to-many too, and the cascades on the owned side of the relationship seem to have no effect(my join table isn't getting updated). Are you sure that cascades can be specified on either side of a bidirectional relationship ? Btw, I am using JPA and not Hibernate, if it has got anything to do....and Thanks...you are always very helpful and elaborate. –  soontobeared  Oct 8 '09 at 12:54
 
@soontobeared As said by ChssPly, mappedBy has nothing to do with cascading. You can use cascade on both sides at the same time, even with bidirectional relationship. If your code has nothing to do with my answer so your JPA provider may not be according to JPA specification. If possible show the code used to remove both User and UserProfile instance. regards, –  Arthur Ronald F D Garcia  Oct 13 '09 at 3:16
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值