ivy
ivy

Reputation: 63

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?

Upvotes: 3

Views: 10342

Answers (1)

K.Nicholas
K.Nicholas

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

Related Questions