A question about JPA Cascade and removing entity

前端 未结 4 724
时光取名叫无心
时光取名叫无心 2021-01-31 12:16

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

Code from User Entity:

@OneToOne(cascade=CascadeType.ALL)
@P         


        
相关标签:
4条回答
  • 2021-01-31 12:40

    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 between A 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.

    0 讨论(0)
  • 2021-01-31 12:49

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

    @OneToMany(orphanRemoval=true)

    check documentation here for more info.

    0 讨论(0)
  • 2021-01-31 13:02

    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.

    0 讨论(0)
  • 2021-01-31 13:03

    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

    0 讨论(0)
提交回复
热议问题