如何实现复合键,让我们做一个非常简单的例子,用户参加 Activity ,三个数据库表:User、Event、Users_Attending_Events 最后一个表有三列:userID、eventID;它们与其他两个表各自的 ID 和 success 相连接,确定用户是否向事件展示。
我希望参加是一个单独的类,并且不要直接加入用户和事件,因为参加包含“成功”信息,并且必须单独管理。
我的实现
用户对象:
@Entity
@Table(name = "[users]")
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer userID;
@JsonIgnore
@OneToMany(mappedBy = "attend", targetEntity = Attending.class, fetch = FetchType.LAZY)
private Set<Attending> attendEvents = new HashSet<Attending>();
...
// setters, getters, constructors, equal and hash ...
}
事件:
@Entity
@Table(name = "events")
public class Event implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer eventID;
@JsonIgnore
@OneToMany(mappedBy = "attend", targetEntity = Attending.class, fetch = FetchType.LAZY)
private Set<Attending> participants = new HashSet<Attending>();
...
// setters, getters, constructors, equal and hash ...
}
参加类(class):
@Entity
@Table(name = "users_attending_events")
public class Attending implements Serializable {
@EmbeddedId
protected AttendingID attend;
private Integer success;
...
// setters, getters, constructors, equal and hash ...
}
AttendingID 类,用于复合键:
@Embeddable
public class AttendingID implements Serializable {
@ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
@JoinColumn(name = "users_userID", referencedColumnName = "userID")
private Integer user;
@ManyToOne(targetEntity = Event.class, fetch = FetchType.LAZY)
@JoinColumn(name = "events_eventID", referencedColumnName = "eventID")
private Integer event;
...
// setters, getters, constructors, equal and hash ...
}
运行时出现异常:
org.hibernate.MappingException: Foreign key (FKlerh9fv4q1rjiusg0ful3m15j:users_attending_events [events_eventID,users_userID])) must have same number of columns as the referenced primary key (users [userID])
我错过了什么?
最佳答案
问题:
异常非常简单,说明映射的外键不是预期的类型,而您的问题是您试图在 Integer 类型的属性中映射
这是错误的部分。@ManyToOne
关系
解决方案:
@ManyToOne
注释应引用您案例中 User
和 Event
的映射 Entity
,而不是基元实体的类型或主键。
但是要定义Embeddable
主键,您有两个选择:
- 仅使用映射实体主键作为
Embeddable
类中的属性。
您的代码将是:
@Embeddable
public class AttendingID implements Serializable {
@Column(name = "users_userID")
private Integer userID;
@Column(name = "events_eventID")
private Integer eventID;
...
// setters, getters, constructors, equal and hash ...
}
- 或者使用两个映射实体作为可嵌入主键中的属性,并通过
@ManyToOne
注释引用它们。
因此,在您的代码中,您只需要更改 user
和
@Embeddable
public class AttendingID implements Serializable {
@ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
@JoinColumn(name = "users_userID", referencedColumnName = "userID")
private User user;
@ManyToOne(targetEntity = Event.class, fetch = FetchType.LAZY)
@JoinColumn(name = "events_eventID", referencedColumnName = "eventID")
private Event event;
...
// setters, getters, constructors, equal and hash ...
}
文档:
要进一步阅读和更多选项,您可以查看 5.1.2.1. Composite identifier Section in Hibernate Mapping Documentation它清楚地显示并解释了映射复合主键的所有可能情况。
<小时/>编辑:
重新阅读你的问题,更好地关注问题并从 vue 的设计角度思考它之后,我认为用 ManyToMany 可以更好地说明你的情况 a ManyToMany
User
和 Event
实体之间的关系,其中连接表 Attending
具有额外列 success
,它将更好地处理您的情况并解决问题。
我建议你看看这个Hibernate Many-to-Many Association with Extra Columns in Join Table Example tutorial它显示了类似的ManyToMany
解决方案。
关于java - Hibernate中复合ID如何映射Key类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43977517/