Jpa 几个@ManyToOne 与 Cascade
Jpa several @ManyToOne with Cascade
我有三个实体,会话、订单和用户(我的在线电影票项目的一部分)。在我的域模型中,Order 保留 User 和 Session 的 fk。正如您在我的代码中看到的那样:
@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<>();
...
}
我的问题是,我可以在 Session 和 User 中使用 CascadeType.ALL
吗?
使用 Session 和 User 更新 Order 时是否存在潜在冲突?
如你所见,我使用fetchType.Lazy,能保证Session和User中的订单都是最新的吗?
问题 1:这是个好问题,但要回答这个问题,您需要了解 owning
实体的概念。带有 @ManyToOne
注释的 Entity
是关系的所有者。这对开发人员很重要,因为除非在拥有方完成,否则不会保留任何关系,在这种情况下,这意味着设置 Order.user
。但是,由于您在 non-owning User
上有 cascade
注释,因此您必须做额外的工作才能使用级联功能:
// 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);
请注意,您必须创建一组订单并设置 Order.user 才能坚持级联。但是,如果您将 cascade
注释放在拥有实体 Order
上,那么您的工作就会变得简单得多:
// 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);
现在只需坚持 order
一次调用即可坚持新的 User
和 Order
。在 Order
实体上没有 cascade
注释,在 User
之前坚持 Order
会给你一个例外。
参考文献: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”?
问题2:FetchType.LAZY
意味着你必须通过特定的查询来获得children,所以如果我理解你的问题,答案是否定的,它不能保证任何事情。使用 FetchType.LAZY
当您获得 Session
时,您将无法访问 Session.orders
当实体分离时,通常是在您离开会话 Bean 或服务层之后。如果您需要访问订单,则需要在 select 查询中获取它们:
"select distinct s from Session s join fetch s.orders"
编辑:如前所述,默认情况下,此查询会执行 sql "inner join",如果没有订单,则 return 什么也不会。相反,做
"select distinct s from Session s left join fetch s.orders"
以便您始终获得数据库中的会话。
参考:Difference between FetchType LAZY and EAGER in Java Persistence API?
我有三个实体,会话、订单和用户(我的在线电影票项目的一部分)。在我的域模型中,Order 保留 User 和 Session 的 fk。正如您在我的代码中看到的那样:
@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<>();
...
}
我的问题是,我可以在 Session 和 User 中使用 CascadeType.ALL
吗?
使用 Session 和 User 更新 Order 时是否存在潜在冲突?
如你所见,我使用fetchType.Lazy,能保证Session和User中的订单都是最新的吗?
问题 1:这是个好问题,但要回答这个问题,您需要了解 owning
实体的概念。带有 @ManyToOne
注释的 Entity
是关系的所有者。这对开发人员很重要,因为除非在拥有方完成,否则不会保留任何关系,在这种情况下,这意味着设置 Order.user
。但是,由于您在 non-owning User
上有 cascade
注释,因此您必须做额外的工作才能使用级联功能:
// 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);
请注意,您必须创建一组订单并设置 Order.user 才能坚持级联。但是,如果您将 cascade
注释放在拥有实体 Order
上,那么您的工作就会变得简单得多:
// 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);
现在只需坚持 order
一次调用即可坚持新的 User
和 Order
。在 Order
实体上没有 cascade
注释,在 User
之前坚持 Order
会给你一个例外。
参考文献: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”?
问题2:FetchType.LAZY
意味着你必须通过特定的查询来获得children,所以如果我理解你的问题,答案是否定的,它不能保证任何事情。使用 FetchType.LAZY
当您获得 Session
时,您将无法访问 Session.orders
当实体分离时,通常是在您离开会话 Bean 或服务层之后。如果您需要访问订单,则需要在 select 查询中获取它们:
"select distinct s from Session s join fetch s.orders"
编辑:如前所述,默认情况下,此查询会执行 sql "inner join",如果没有订单,则 return 什么也不会。相反,做
"select distinct s from Session s left join fetch s.orders"
以便您始终获得数据库中的会话。
参考:Difference between FetchType LAZY and EAGER in Java Persistence API?