What Is the Meaning of the Cascadetype.All for a @Manytoone JPA Association

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

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.

Hibernate: When should I use Cascade.ALL and when should i specify them separately

Cascading is about persistence actions involving one object propagating to other objects via an association.

Cascading can apply to a variety of Hibernate actions, and it is typically transitive. The "cascade=CascadeType..." attribute of the annotation that defines the association says what actions should cascade for that association.

Cascade = "all" means to apply all primary cascade types.

As of Hibernate 5.3, these types are:

  • "delete" / "remove",
  • "detach" / "evict",
  • "merge",
  • "lock",
  • "persist",
  • "refresh",
  • "replicate",
  • "save_update" / "update"

(Some of those cascade type names are old and/or deprecated.)

There are three more compound types:

  • "all_delete_orphan" - means the same as "all" plus enabling the deletion of entities that are orphaned by the cascading.
  • "delete_orphan" - means "delete" plus orphan deletion.
  • "none" - means no cascading.

Jpa several @ManyToOne with Cascade

Question 1: It's a good question, but in order to answer it you need to understand the concept of the owning entity. The Entity with the @ManyToOne annotation is the owner of the relationship. This is important for the developer because no relationship will be persisted unless it's done on the owning side, in this case that means setting Order.user. However, since you have the cascade annotation on the non-owning User, you have to do extra work to use the cascade functionality:

// create Order
Order order = new Order();
// create User and Set of orders
User user = new User();
Set<Order> userOrders = new HashSet<Order>();
user.setOrders(userOrders);
userOrders.add(order);
// and set Order.user
order.setUser(user);
// persist with cascade
em.persist(user);

Notice that you must create a Set of orders as well as set Order.user to persist with cascade. However, if you put the cascade annotation on the owning entity Order, then your job becomes much simpler:

// create User
User user = new User();
// create Order
Order order = new Order();
// and set Order.user
order.setUser(user);
// persist with cascade
em.persist(order);

Now just persisting order will persist the new User and the Order with one call. Without the cascade annotation on the Order entity, persisting Order before User will give you an exception.

References: What is the “owning side” in an ORM mapping?, In a bidirectional JPA OneToMany/ManyToOne association, what is meant by “the inverse side of the association”?

Question 2: FetchType.LAZY means you have to get the children by specific query, so if I understand your question, the answer is no, it doesn't guarantee anything. With FetchType.LAZY when you get a Session you will not have access to the Session.orders when the entity becomes detached, typically after you have left your Session Bean or Service Layer. If you need access to orders, you will need to get them in the select query:

"select distinct s from Session s join fetch s.orders"

EDIT: As noted, by default this query does a sql "inner join", which will return nothing if there are no orders. Instead, do

"select distinct s from Session s left join fetch s.orders"

so that you always get the sessions that are in the database.

Reference: Difference between FetchType LAZY and EAGER in Java Persistence API?

JPA OneToMany persist with CascadeType.ALL doesn't persist child

You're mixing two very different concepts.

A CascadeType deals with what actions cascade to relations. When specifying CascadeType.ALL, you are telling the persistence provider that whenever you persist, merge, or remove that entity, those actions are to be replicated to the relations.

But in order for cascade operations to work, you must first make sure that the relationship is managed correctly. If you look at Vlad's post, you'll notice two very important methods on Post.

public void addDetails(PostDetails details) {
this.details = details;
details.setPost( this );
}

public void removeDetails() {
this.details.setPost( null );
this.details = null;
}

These methods make sure that the relationship between a PostDetails and a Post is properly maintained based on your requirements. So assuming the following mapping:

public class Post {
@OneToOne(cascade = CascadeType.ALL, mappedBy = "post", orphanRemoval = true)
private PostDetails details;
}

You could perform the persistence operation of both of them as follows:

PostDetails details = new PostDetails();
details.setUser( currentUser );
Post post = new Post();
post.addDetails( details );
session.persist( post );

You notice I used the addDetails rather than the typical setDetails because I wanted to make sure that the relationship between Post and PostDetails was initialized.

Hope that helps.

JPA: CascadeType.PERSIST with ManyToOne

Actually, the order in which entities are persisted determines the order in which insert statements are generated, so everything behaves as documented. See this answer also for more details.

Comment is persisted first (you explicitly persist it first), then Article would be persisted by cascade.

The correct approach is to persist Article first, as you already pointed out.

Hibernate @ManyToOne only works with CascadeType.ALL

Probably you need to enable Hibernate custom @Cascade when using non-JPA Session.saveOrUpdate() method.

Add @Cascade(org.hibernate.annotations.CascadeType.SAVE_UPDATE) or use Session.persist()



Related Topics



Leave a reply



Submit