Java 如何正确映射主键由两个外键组成的实体,其中一个外键本身是复合键?

Java 如何正确映射主键由两个外键组成的实体,其中一个外键本身是复合键?,java,jpa,orm,foreign-keys,composite-key,Java,Jpa,Orm,Foreign Keys,Composite Key,我很难想出如何在特定的数据库设计上正确地执行ORM 我的模式由三个表组成:用户表、审阅表和投票表。用户可以发布相册的评论,也可以为任何评论指定正面或负面评级。相册是从外部API提供的,因此架构中缺少它们的表,但它们的ID被引用 用户主键仅由其用户名组成。审阅主键由审阅者的用户名(外键)和审阅的相册ID组成。最后,投票主键由投票者的用户名、外键和已投票审阅的主键组成,如前所述,包括审阅者的用户名和审阅的相册ID 用户可以为每个专辑发布评论,也可以为每个评论分配投票 这是表示模式的ER模型: 为了

我很难想出如何在特定的数据库设计上正确地执行ORM

我的模式由三个表组成:用户表、审阅表和投票表。用户可以发布相册的评论,也可以为任何评论指定正面或负面评级。相册是从外部API提供的,因此架构中缺少它们的表,但它们的ID被引用

用户主键仅由其用户名组成。审阅主键由审阅者的用户名(外键)和审阅的相册ID组成。最后,投票主键由投票者的用户名、外键和已投票审阅的主键组成,如前所述,包括审阅者的用户名和审阅的相册ID

用户可以为每个专辑发布评论,也可以为每个评论分配投票

这是表示模式的ER模型:

为了映射实体ID,我使用了
@IdClass
注释,但我不确定方向是否正确。我还尝试使用
@EmbeddedId
注释,但结果是一样的

到目前为止,我的实体类就是这样的:

@实体
公共类用户实现可序列化{
私有静态最终长serialVersionUID=1;
@Id@Column(name=“username”)
私有字符串用户名;
@列(unique=true,nullable=false)
私人字符串电子邮件;
@列(name=“password”,null=false)
私有字符串密码;
@Temporal(TemporalType.TIMESTAMP)@Column(name=“signUpDate”,nullable=false)
私人日期更新;
//空构造函数、getter、setter、equals和hashCode实现
}
@Entity@IdClass(ReviewId.class)
公共类审阅实现了可序列化{
私有静态最终长serialVersionUID=1;
@Id@ManyToOne@JoinColumn(name=“reviewerUsername”,referencedColumnName=“username”)
私人用户审查员;
@Id@Column(name=“ReviewDalbumid”)
私人长时间评论;
@列(name=“content”,null=false,长度=2500)
私有字符串内容;
@列(name=“rating”,nullable=false)
私人整数评级;
@Temporal(TemporalType.TIMESTAMP)@Column(name=“publicationDate”,nullable=false)
私人日期公布日期;
//空构造函数、getter、setter、equals和hashCode实现
}
@Entity@IdClass(VoteId.class)
公共类投票实现可序列化{
私有静态最终长serialVersionUID=1;
@Id@ManyToOne@JoinColumn(name=“voterUsername”,referencedColumnName=“username”)
私人用户投票人;
@Id@ManyToOne@JoinColumns({
@JoinColumn(name=“reviewerUsername”,referencedColumnName=“reviewerUsername”),
@JoinColumn(name=“ReviewDalbumId”,referencedColumnName=“ReviewDalbumId”)
})
私人审查;
@Column(name=“vote”)/@todo add属性nullable=false
私人布尔投票;
//空构造函数、getter、setter、equals和hashCode实现
}
以下是我的ID类:

public类ReviewId实现可序列化{
私有静态最终长serialVersionUID=1L;
私人用户审查员;
私人长时间评论;
//空构造函数、getter、setter、equals和hashCode实现
}
公共静态类VoteId实现可序列化{
私有静态最终长serialVersionUID=1L;
私人用户投票人;
私人审查;
//空构造函数、getter、setter、equals和hashCode实现
}
下面是用于生成模式的MySQL脚本的内容:

如果存在AlbumReviews数据库,则删除模式;
创建模式数据库;
使用AlbumReviews数据库;
创建表用户(
用户名VARCHAR(20)主键,
电子邮件VARCHAR(254)非空唯一,
密码字符(60)不为空,
signUpDate TIMESTAMP NOT NULL默认值now()
)引擎=INNODB;
创建表审阅(
reviewerUsername VARCHAR(20)不为空,
ReviewDalbumid BIGINT(20)不为空,
内容文本不为空,
额定值SMALLINT无符号非空,
publicationDate时间戳非空默认值now(),
检查(评级>=0和评级这些关系是“派生标识”;因此您的ID类应该如下所示(注意外键字段的类型与其对应的实体字段的类型不同):

public类ReviewId实现可序列化{
私有静态最终长serialVersionUID=1L;
private String reviewer;//匹配@Id属性的名称和用户PK的类型
私人长时间评论;
// ...
}
公共静态类VoteId实现可序列化{
私有静态最终长serialVersionUID=1L;
私有字符串voter;//匹配@Id属性的名称和用户PK的类型
private ReviewId review;//匹配@Id属性的名称和review PK的类型
// ...
}
第2.4.1节中讨论了衍生恒等式(带有示例)

另外,作为旁注,
@IdClass
有点老派,而
@EmbeddedId
更干净,消除了实体及其键中重复的代码

<openjpa-2.4.2-r422266:1777108 fatal user error> org.apache.openjpa.util.MetaDataException: The id class specified by type "class application.model.Review" does not match the primary key fields of the class.  Make sure your identity class has the same primary keys as your persistent type, including pk field types. Mismatched property: "reviewer"