具有复合键的单边 OneToMany 也是外键,应该使用@IdClass 还是@Embeddable?

Unilateral OneToMany with Composite Key that is also a Foreign Key, should use @IdClass or @Embeddable?

我很难决定是使用@IdClass 还是@Embeddable 来为如下所示的OneToMany 数据库关系建模复合主键。

user_idusertable的主键,user_merchant同时使用merchant_iduser_id作为组合键.一个用户可以与多个商家打交道,反之亦然。 user_merchant table 跟踪用户和商家之间的关系。

由于“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;

}

对于商家实体来说,这有点棘手。

public class Merchant implements Serializable{

    @Column
    private String merchantId;

    .....

}

运行如果在Merchantclass中没有指定@Id,这段代码将失败。我不确定在这种情况下我是否应该使用@IdClass 或@Embedded/@Embeddable,以及其中一个比另一个有什么好处。

我能否避免像大多数解决方案那样在 Merchant class 中引入新的用户对象?因为商家真的不需要了解用户。

@Id
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "location_id")
private User user;

User 对象第一次保存时,如何填充此字段?如果可能的话,我认为我不需要在已经是同一用户对象的属性的商家对象中使用另一个用户引用。

提前致谢!

我是这样解决这个问题的:

我已经确定这种关系是 parent 和 child object 之间的单边 One-To-Many 关系,其中 child 是复合关系主键部分由来自 parent 的外键组成。

最后,我选择使用@IdClass,因为我仍然需要访问merchantId,而且这似乎是最简单的方法。

我在用户 Class 中所做的唯一更改是在 @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);
            });
        }
    }

}

至于商家 class,我通过@IdClass 将 MerchantPK.class 链接到 Merchant.java。

我还确保了@JoinColumn 中的 insertableupdatable = false,因为这种关系是单方面的,应该只是 parent 一方的 insertable/updatable(用户).

@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;

}

在单边 One-To-Many 关系的情况下,只需要 1 个 @JoinColumn,在这种情况下,它就是 @ManyToOne 所在的位置。带有@OneToMany 的object 仍然是关系的所有者,即使在使用mappedBy 时也是如此,因为我们指定了insertable = falseupdatable = false