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
Why Are Interface Variables Static and Final by Default
How Can a String Be Initialized Using " "
What Are Runtime.Getruntime().Totalmemory() and Freememory()
Importing Two Classes with Same Name. How to Handle
How to Get Parameters from the Url with Jsp
When to Use Abstract Class or Interface
Practical Uses for Atomicinteger
How to Re-Run Failed Junit Tests Immediately
Synchronizing on String Objects in Java
Java: How to Split an Arraylist in Multiple Small Arraylists
"Integer Number Too Large" Error Message for 600851475143
When Is the @JSONproperty Property Used and What Is It Used For
Java Random Numbers Using a Seed
Useful Example of a Shutdown Hook in Java
How to Use Annotations to Define Different Types of Relationships in Hibernate 4 and Spring