java - 单边 OneToMany 复合键也是外键,应该使用@IdClass 还是@Embeddable?
问题描述
我很难决定是使用 @IdClass 还是 @Embeddable 来为如下所示的 OneToMany 数据库关系建模复合主键。
user_id
是user
表的主键,并user_merchant
同时使用merchant_id
和user_id
作为其复合键。一个用户可以与多个商家打交道,反之亦然。该user_merchant
表跟踪用户和商家之间的关系。
由于 ' user
' 是唯一需要了解其关系的人,而不是商家,因此我将其建模为单向的一对多关系。
在用户实体中,我希望像这样建模:
@Entity
@Table(name = "user")
public class User extends Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Long userId;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private Set<Merchant> merchants;
}
对于 Merchant 实体来说,这有点棘手。
public class Merchant implements Serializable{
@Column
private String merchantId;
.....
}
Merchant
如果在类中未指定 @Id,则运行这段代码将失败。我不确定在这种情况下是否应该使用@IdClass 或@Embedded/@Embeddable,以及两者相比有什么好处。
我可以避免像大多数解决方案显示的那样在 Merchant 类中引入新的 User 对象吗?由于商家并不真正需要了解用户。
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "location_id")
private User user;
以及如何User
在第一次保存对象时填充此字段?如果可能的话,我认为我不需要在已经是同一用户对象的属性的商家对象中使用另一个用户引用。
提前致谢!
解决方案
这是我解决这个问题的方法:
我已将这种关系确定为父对象和子对象之间的单边一对多关系的情况,其中子对象的复合主键部分由父对象的外键组成。
最后,我选择使用@IdClass
,因为我仍然需要访问 MercerId,这似乎是最简单的方法。
我在用户类中所做的唯一更改是在 @OneToMany中删除@JoinColumn(name = "user_id")
并替换它。mappedBy = "user"
如果没有此更改,第一次保留此实体就可以正常工作,但是当我尝试在从集合中删除商家的同时更新此实体时,它给了我一些错误。
@Entity
@Table(name = "user")
public class User extends Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column
private Long userId;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true,
mappedBy = "user", fetch = FetchType.LAZY)
private Set<Merchant> merchants;
@PrePersist
public void prePersistUser() {
if (this.merchants != null) {
this.merchants.forEach(merchant-> {
merchant.setUser(this);
});
}
}
}
至于商家类,我MerchantPK.class
通过@IdClass 链接到 Merchant.java。
我还确保在@JoinColumn 内部insertable
, updatable = false
因为这种关系是单方面的,并且只能从父方(用户)插入/更新。
@Entity
@IdClass(MerchantPK.class)
@Table(name = "user_merchant")
public class Merchant {
@Id
@Column(nullable = false)
private String merchantId;
@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id", insertable = false, updatable = false)
private UserEntity user;
}
在单边一对多关系的情况下,只需要 1 个 @JoinColumn,在这种情况下,它就是 @ManyToOne 所在的位置。带有@OneToMany 的对象仍然是关系的所有者,即使使用 mappedBy,因为我们指定了insertable = false
and updatable = false
。
推荐阅读
- sas - sas按组将最后一个值更改为第一个值
- python - 将文本文件转换为 df
- c# - 在 Unity3D 的 System.Drawing 中找不到位图
- python - 有没有什么方法可以用关键字、日期来提取
- typescript - TypeScript:按类型属性选择数组的元素
- android - 处理从新的 Google 相册应用中选择的文件的正确方法
- android - xml 中的 new Date() 不能与数据绑定一起工作
- python - 使用 psql 10.9 和使用 python3.7 的 sqlalchemy 从隔离事务返回行
- python - 如何根据条件更新火花数据框中的行
- spring - TransactionalEventListener 不会启动