【发布时间】:2016-05-10 16:17:59
【问题描述】:
我有以下领域模型
users
----
id (PK)
name
orders
------
id (PK)
userid (PK)
name
Orders.userid 引用 User 中的 id 并且是复合主键的一部分。 (我需要主键中的用户 ID,因为它是一个分区键,在 MySQL 中我们无法在没有分区键的情况下创建主键)
关于使用 JPA 更新用户,如果我尝试使用清除关联的订单集合
User user = userRepository.getOne(id);
user.getOrders().clear();
userRepository.save(user);
JPA 首先尝试在关联的 Orders 上将 userid 设置为 null,然后删除该行。这失败了,因为 userid 是不可为空的并且是主键的一部分。有没有办法告诉 JPA 它只需要删除 Order 行而不先将 userid 列设置为 null?
更新
映射: 我的映射是这样的:
@Entity
@Table(name = "users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id")
public Long id;
@Column(name="name")
private String name;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name="userid", referencedColumnName = "id", insertable = true, updatable = true)
@Fetch(FetchMode.JOIN)
private Set<Order> orders;
}
@Entity
@Table(name = "orders")
@IdClass(Order.OrderPk.class)
public class Order implements Serializable {
@Id
@Column(name="id")
private Long id;
@Id
@Column(name="userid")
private Long userId;
@Column(name="name")
private String name;
public static class OrderPk implements Serializable {
private Long id;
private Long userId;
}
}
你能告诉我映射会有什么变化吗?
更新:
也尝试了以下映射:
@Entity
@Table(name = "users")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name="id", nullable = false)
public Long id;
@Column(name="name")
private String name;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.EAGER, mappedBy = "orderPk.user")
@Fetch(FetchMode.JOIN)
private Set<Order> orders;
}
@Entity
@Table(name = "orders")
public class Order implements Serializable {
@EmbeddedId
private OrderPk orderPk;
@Column(name="name")
private String name;
@Embeddable
public static class OrderPk implements Serializable {
@GeneratedValue
@Column(name="id", insertable = false, updatable = false, nullable = false)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name="userid", referencedColumnName = "id", insertable = false, updatable = false, nullable = false)
private User user;
}
}
在插入时,它抱怨说“为:类订单生成空 id” (也尝试过 insertable=true 和 updatable=true)
【问题讨论】:
-
修复您的映射,除此之外,这确实是清除托管集合的一种糟糕方法。您不应允许从
User对象外部修改集合。或者甚至可以完全从User中删除订单,只在订单上留下User字段并简单地创建一个查询。 -
@M.Deinum 感谢您的回复,我已经用映射更新了问题。您能告诉我可以进行哪些更改吗?
-
本质上,我在问如何处理具有非空外键的子实体。插入也将尝试首先使用 NULL 外键值插入,然后尝试将其更新为父键。在这种情况下插入会失败,因为数据库不允许 NULL。
-
订单上真的需要组合PK吗?至少将其设置为
updatable=false和nullable=false。 -
@M.Deinum,是的,我确实需要组合 PK,因为分区键需要成为 PK 的一部分。将其设置为 updateable=false 和 nullable=false 似乎无法解决问题。
标签: java mysql spring jpa spring-data