ChatGPT解决这个技术问题 Extra ChatGPT

What is the meaning of the CascadeType.ALL for a @ManyToOne JPA association

I think I misunderstood the meaning of cascading in the context of a @ManyToOne relationship.

The case:

public class User {

   @OneToMany(fetch = FetchType.EAGER)
   protected Set<Address> userAddresses;

}

public class Address {

   @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
   protected User addressOwner;

}

What is the meaning of the cascade = CascadeType.ALL? For example, if I delete a certain address from the database, how does the fact that I added the cascade = CascadeType.ALL affect my data (the User, I guess)?


k
kostja

The meaning of CascadeType.ALL is that the persistence will propagate (cascade) all EntityManager operations (PERSIST, REMOVE, REFRESH, MERGE, DETACH) to the relating entities.

It seems in your case to be a bad idea, as removing an Address would lead to removing the related User. As a user can have multiple addresses, the other addresses would become orphans. However the inverse case (annotating the User) would make sense - if an address belongs to a single user only, it is safe to propagate the removal of all addresses belonging to a user if this user is deleted.

BTW: you may want to add a mappedBy="addressOwner" attribute to your User to signal to the persistence provider that the join column should be in the ADDRESS table.


It could be good to have CascadeType.ALL on @OneToMany side though.
V
Vlad Mihalcea

You shouldn't use CascadeType.ALL on @ManyToOne since entity state transitions should propagate from parent entities to child ones, not the other way around.

The @ManyToOne side is always the Child association since it maps the underlying Foreign Key column.

Therefore, you should move the CascadeType.ALL from the @ManyToOne association to the @OneToMany side, which should also use the mappedBy attribute since it's the most efficient one-to-many table relationship mapping.


Thanks Vlad, I'm not sure why this is not a topmost answer.
C
Community

See here for an example from the OpenJPA docs. CascadeType.ALL means it will do all actions.

Quote:

CascadeType.PERSIST: When persisting an entity, also persist the entities held in its fields. We suggest a liberal application of this cascade rule, because if the EntityManager finds a field that references a new entity during the flush, and the field does not use CascadeType.PERSIST, it is an error. CascadeType.REMOVE: When deleting an entity, it also deletes the entities held in this field. CascadeType.REFRESH: When refreshing an entity, also refresh the entities held in this field. CascadeType.MERGE: When merging entity state, also merge the entities held in this field.

Sebastian


New in JPA, this information is usefull but what about Detach here?
In CascadeType.DETACH, when detaching an entity, em also detach the entities held by parent entity.
C
Community

From the EJB3.0 Specification:

Use of the cascade annotation element may be used to propagate the effect of an operation to associated entities. The cascade functionality is most typically used in parent-child relationships. If X is a managed entity, the remove operation causes it to become removed. The remove operation is cascaded to entities referenced by X, if the relationships from X to these other entities is annotated with the cascade=REMOVE or cascade=ALL annotation element value.

So in a nutshell, entity relationships defined with CascadeType.All will ensure that all persistence events such as persist, refresh, merge and remove that occur on the parent, will be passed to the child. Defining other CascadeType options provides the developer with a more granular level of control over how the entity association handles persistence.

For example if I had an object Book that contained a List of pages and I add a page object within this list. If the @OneToMany annotation defining the association between Book and Page is marked as CascadeType.All, persisting the Book would result in the Page also being persisted to the database.


l
lehins

In JPA 2.0 if you want to delete an address if you removed it from a User entity you can add orphanRemoval=true (instead of CascadeType.REMOVE) to your @OneToMany.

More explanation between orphanRemoval=true and CascadeType.REMOVE is here.


N
Negar Zamiri

If you just want to delete the address assigned to the user and not to affect on User entity class you should try something like that:

@Entity
public class User {
   @OneToMany(mappedBy = "addressOwner", cascade = CascadeType.ALL)
   protected Set<Address> userAddresses = new HashSet<>();
}

@Entity 
public class Addresses {
   @ManyToOne(cascade = CascadeType.REFRESH) @JoinColumn(name = "user_id")
   protected User addressOwner;
}

This way you dont need to worry about using fetch in annotations. But remember when deleting the User you will also delete connected address to user object.