Reputation: 63
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?
Upvotes: 3
Views: 10342
Reputation: 11561
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?
Upvotes: 9