ivy ivy - 6 months ago 19
Java Question

Jpa several @ManyToOne with Cascade

I have got three entities, Session, Order and User (part of my online movie tickets project). In my domain model, Order keeps fk of both User and Session. As you can see in my code:




@Table(name="Orders")
@Entity

public class Order {
@ManyToOne
@JoinColumn(nullable = false)
private User user;

@ManyToOne
private Session session;
...
}



@Entity
@Table(name="Session")

public class Session {
@OneToMany(fetch=FetchType.LAZY,
cascade = CascadeType.ALL,
mappedBy = "session")
private List<Order> orders = new ArrayList<Order>();
...
}



@Table(name="User")
@Entity

public class User {
@OneToMany(cascade = { CascadeType.PERSIST,
CascadeType.MERGE,
CascadeType.REMOVE },
mappedBy = "user")
private @Getter Set<Order> orders = new HashSet<>();
...
}





My question is, Can I use
CascadeType.ALL
in both Session and User?
Are there potential conflicts when update Order with both Session and User?




As you can see, I use fetchType.Lazy, Can it guarantee that orders in both Session and User are up-to-date?

Answer

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"

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