我正在创建一种社交网络,我有可以跟随其他用户的用户。所以我有一个实体,像:
@Entity
public class FollowedUser{
@ManyToOne
private User user;
@ManyToOne
private User followedUser;
//more fields
...
}
我不能有许多关系,因为我有更多的字段在我的followweduser实体。现在,我的问题是:
- 应该使用复合键还是生成的id(代理键)?我已经阅读了以下关于建议使用代理键的主题的链接(1,2,3),但我不知道它们是否适用于我的具体情况(我的复合键将由两个代理外键组成)。还有这里(4)它说"复合主键通常在从遗留数据库映射时出现",所以我想它们是不鼓励的。
- 如果我应该使用复合键,我不知道我是否应该使用@IdClass(如这里推荐的5)或@EmbeddedId(如这里推荐的6)或任何其他选项。虽然我想这并不重要。
- 如果我应该使用代理键,我不知道如何使复合候选键不可能重复。我在这里读过(7)关于唯一索引,但我不知道这是否是解决这个问题的正确方法。
1。我建议使用代理键。我发现将记录的数据库标识与其业务标识分开是有帮助的。如果这两个概念混合在一起,对它们进行正确的建模并在以后重新建模可能会很麻烦。你引用了一些好的答案,所以你可能知道主要的优点和缺点,没有必要在这里重申。另外一点是,您可以依赖像UUID
这样的代理键来正确地实现equals
和hashCode
。为组合键实现这些功能以很好地处理集合和数据库可能会很棘手。
对于您的用例,用户之间的连接可以被视为自己的实体,并具有自动生成的代理PK。您可以在DB中强制执行业务键属性的唯一性,参见第3条。
2。老实说,在EmbeddedId
和IdClass
之间选择主要是一个品味问题。我更喜欢IdClass
,因为它避免了在查询id属性时添加导航:
... WHERE a.id.attribute = :att
与EmbeddedId
对比
... WHERE a.attribute = :att
vs. with IdClass
我不认为你的论点有说服力。组合键往往由实体的最具特征的属性组成。把它们隐藏在一个不同的类中,因为它们碰巧被用作DB键,对我来说似乎很尴尬。
3。唯一索引看起来是保证属性组合唯一性的好方法。你可能想读读这个答案,这里有一个小例子。
如果您还没有使用JPA 2.1,您可能想要使用唯一的约束,正如这里所解释的。