JPA/Hibernate 在等待复合主 farzine 键时进行映射
JPA/Hibernate Composite Primary Foriegn Key ManyToOne Mapping
***已解决 - 更新了分辨率***
我有两个表:
notification - 由 UserId + NotificationDetail
组成的复合键
notification_detail - 单个主键
我想使用 JPA 来保存和读取这些对象,但无法使 ManyToOne 映射起作用。
多个通知映射到一个notification_detail.
表:
create table notification(
notification_user_id int not null,
notification_detail_id int not null,
notification_status_cd int not null,
primary key(notification_user_id, notification_detail_id),
constraint pkey_notification_detail foreign key(notification_detail_id) references notification_detail(notification_detail_id),
constraint pkey_notification_status_cd foreign key(notification_status_cd) references lk_notification_status(notification_status_id)
);
create table notification_detail (
notification_detail_id int auto_increment,
notification_type_cd int not null,
notification_message varchar(50) not null,
primary key(notification_detail_id),
constraint pkey_notification_type_cd foreign key(notification_type_cd) references lk_notification_type(notification_type_id)
);
***已解决并正确设置 JPA:***
class NotificationId implements Serializable {
private static final long serialVersionUID = 1L;
Integer notificationUserId;
Integer details;
public Integer getNotificationUserId() {
return notificationUserId;
}
public void setNotificationUserId(Integer notificationUserId) {
this.notificationUserId = notificationUserId;
}
public Integer getDetails() {
return details;
}
public void setDetails(Integer details) {
this.details = details;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((details == null) ? 0 : details.hashCode());
result = prime * result + ((notificationUserId == null) ? 0 : notificationUserId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NotificationId other = (NotificationId) obj;
if (details == null) {
if (other.details != null)
return false;
} else if (!details.equals(other.details))
return false;
if (notificationUserId == null) {
if (other.notificationUserId != null)
return false;
} else if (!notificationUserId.equals(other.notificationUserId))
return false;
return true;
}
}
@Entity
@Table(name="notification")
@IdClass(NotificationId.class)
public class Notification implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@NotNull
private Integer notificationUserId;
@Id
@NotNull
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="notification_detail_id")
private NotificationDetail details;
@NotNull
private Integer notificationStatusCd;
@NotNull
private Integer updateUserId;
public Integer getNotificationUserId() {
return notificationUserId;
}
public void setNotificationUserId(Integer notificationUserId) {
this.notificationUserId = notificationUserId;
}
public NotificationDetail getDetails() {
return details;
}
public void setDetails(NotificationDetail details) {
this.details = details;
}
public Integer getNotificationStatusCd() {
return notificationStatusCd;
}
public void setNotificationStatusCd(Integer notificationStatusCd) {
this.notificationStatusCd = notificationStatusCd;
}
public Integer getUpdateUserId() {
return updateUserId;
}
public void setUpdateUserId(Integer updateUserId) {
this.updateUserId = updateUserId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((details == null) ? 0 : details.hashCode());
result = prime * result + ((notificationStatusCd == null) ? 0 : notificationStatusCd.hashCode());
result = prime * result + ((notificationUserId == null) ? 0 : notificationUserId.hashCode());
result = prime * result + ((updateUserId == null) ? 0 : updateUserId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Notification other = (Notification) obj;
if (details == null) {
if (other.details != null)
return false;
} else if (!details.equals(other.details))
return false;
if (notificationStatusCd == null) {
if (other.notificationStatusCd != null)
return false;
} else if (!notificationStatusCd.equals(other.notificationStatusCd))
return false;
if (notificationUserId == null) {
if (other.notificationUserId != null)
return false;
} else if (!notificationUserId.equals(other.notificationUserId))
return false;
if (updateUserId == null) {
if (other.updateUserId != null)
return false;
} else if (!updateUserId.equals(other.updateUserId))
return false;
return true;
}
}
@Entity
@Table(name="notification_detail")
public class NotificationDetail implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer notificationDetailId;
@NotNull
private Integer notificationTypeCd;
@NotNull
private String notificationMessage;
@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="details")
private Set<Notification> notifications;
@NotNull
private Integer updateUserId;
public Integer getNotificationDetailId() {
return notificationDetailId;
}
public void setNotificationDetailId(Integer notificationDetailId) {
this.notificationDetailId = notificationDetailId;
}
public Integer getNotificationTypeCd() {
return notificationTypeCd;
}
public void setNotificationTypeCd(Integer notificationTypeCd) {
this.notificationTypeCd = notificationTypeCd;
}
public String getNotificationMessage() {
return notificationMessage;
}
public void setNotificationMessage(String notificationMessage) {
this.notificationMessage = notificationMessage;
}
public Set<Notification> getNotifications() {
return notifications;
}
public void setNotifications(Set<Notification> notifications) {
this.notifications = notifications;
}
public void addNotification(Notification notification){
if(notifications == null)
notifications = new HashSet<Notification>();
notifications.add(notification);
}
public Integer getUpdateUserId() {
return updateUserId;
}
public void setUpdateUserId(Integer updateUserId) {
this.updateUserId = updateUserId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((notificationDetailId == null) ? 0 : notificationDetailId.hashCode());
result = prime * result + ((notificationMessage == null) ? 0 : notificationMessage.hashCode());
result = prime * result + ((notificationTypeCd == null) ? 0 : notificationTypeCd.hashCode());
result = prime * result + ((notifications == null) ? 0 : notifications.hashCode());
result = prime * result + ((updateUserId == null) ? 0 : updateUserId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NotificationDetail other = (NotificationDetail) obj;
if (notificationDetailId == null) {
if (other.notificationDetailId != null)
return false;
} else if (!notificationDetailId.equals(other.notificationDetailId))
return false;
if (notificationMessage == null) {
if (other.notificationMessage != null)
return false;
} else if (!notificationMessage.equals(other.notificationMessage))
return false;
if (notificationTypeCd == null) {
if (other.notificationTypeCd != null)
return false;
} else if (!notificationTypeCd.equals(other.notificationTypeCd))
return false;
if (notifications == null) {
if (other.notifications != null)
return false;
} else if (!notifications.equals(other.notifications))
return false;
if (updateUserId == null) {
if (other.updateUserId != null)
return false;
} else if (!updateUserId.equals(other.updateUserId))
return false;
return true;
}
}
JPA 用法:
NotificationDetail details = new NotificationDetail();
details.setMessage("Hello");
details.setTypeCd(NotificationTypeEnum.INFO);
detail.setUpdateUserId(userId);
Notification notif = new Notification();
notif.setNotifiedUserId(userId);
notif.setStatusCd(NotificationStatusEnum.UNREAD);
notif.setDetails(details);
notificationRepository.save(notif);
***此错误现已解决***:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'notificati0_.details_notificationDetailId' in 'field list'
***原题:***
我已经尝试了所有类型的不同配置。我能想到的最好的是我的情况很复杂,因为父对象 "notification" 有一个复合键 "notification_detail_id" ,它也是子对象的主键。这使得Hibernate很难先持久化child,然后取key保存给parent。
我意识到我的注释某处不正确,但就是想不通。
看起来你正在处理 "derived identity"。将您的 类 更改为如下所示:
class NotificationId implements Serializable {
private static final long serialVersionUID = 1L;
Integer notifiedUserId;
Integer details;
...
}
@Entity
@IdClass(NotificationId.class)
@Table(name="notification")
public class Notification implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@NotNull
@Column(name="notification_user_id")
private Integer notifiedUserId;
@Id
@NotNull
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="notification_detail_id")
private NotificationDetail details;
@NotNull
@Column(name="notification_status_cd")
private Integer statusCd;
@Column(name="update_timestamp")
private Date timestamp;
...
}
注意:
NotificationId.notificationDetailId
已重命名为 details
以匹配 Notification
中的相应字段
Notification.notificationDetailId
已删除
Notification.details
已被标记为 @Id
您的字段模型似乎暗示您应该对 Notification
和 User
之间的关系做同样的事情。
派生身份在 JPA 2.1 规范的第 2.4.1 节中进行了讨论。
***已解决 - 更新了分辨率***
我有两个表:
notification - 由 UserId + NotificationDetail
组成的复合键notification_detail - 单个主键
我想使用 JPA 来保存和读取这些对象,但无法使 ManyToOne 映射起作用。
多个通知映射到一个notification_detail.
表:
create table notification(
notification_user_id int not null,
notification_detail_id int not null,
notification_status_cd int not null,
primary key(notification_user_id, notification_detail_id),
constraint pkey_notification_detail foreign key(notification_detail_id) references notification_detail(notification_detail_id),
constraint pkey_notification_status_cd foreign key(notification_status_cd) references lk_notification_status(notification_status_id)
);
create table notification_detail (
notification_detail_id int auto_increment,
notification_type_cd int not null,
notification_message varchar(50) not null,
primary key(notification_detail_id),
constraint pkey_notification_type_cd foreign key(notification_type_cd) references lk_notification_type(notification_type_id)
);
***已解决并正确设置 JPA:***
class NotificationId implements Serializable {
private static final long serialVersionUID = 1L;
Integer notificationUserId;
Integer details;
public Integer getNotificationUserId() {
return notificationUserId;
}
public void setNotificationUserId(Integer notificationUserId) {
this.notificationUserId = notificationUserId;
}
public Integer getDetails() {
return details;
}
public void setDetails(Integer details) {
this.details = details;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((details == null) ? 0 : details.hashCode());
result = prime * result + ((notificationUserId == null) ? 0 : notificationUserId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NotificationId other = (NotificationId) obj;
if (details == null) {
if (other.details != null)
return false;
} else if (!details.equals(other.details))
return false;
if (notificationUserId == null) {
if (other.notificationUserId != null)
return false;
} else if (!notificationUserId.equals(other.notificationUserId))
return false;
return true;
}
}
@Entity
@Table(name="notification")
@IdClass(NotificationId.class)
public class Notification implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@NotNull
private Integer notificationUserId;
@Id
@NotNull
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="notification_detail_id")
private NotificationDetail details;
@NotNull
private Integer notificationStatusCd;
@NotNull
private Integer updateUserId;
public Integer getNotificationUserId() {
return notificationUserId;
}
public void setNotificationUserId(Integer notificationUserId) {
this.notificationUserId = notificationUserId;
}
public NotificationDetail getDetails() {
return details;
}
public void setDetails(NotificationDetail details) {
this.details = details;
}
public Integer getNotificationStatusCd() {
return notificationStatusCd;
}
public void setNotificationStatusCd(Integer notificationStatusCd) {
this.notificationStatusCd = notificationStatusCd;
}
public Integer getUpdateUserId() {
return updateUserId;
}
public void setUpdateUserId(Integer updateUserId) {
this.updateUserId = updateUserId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((details == null) ? 0 : details.hashCode());
result = prime * result + ((notificationStatusCd == null) ? 0 : notificationStatusCd.hashCode());
result = prime * result + ((notificationUserId == null) ? 0 : notificationUserId.hashCode());
result = prime * result + ((updateUserId == null) ? 0 : updateUserId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Notification other = (Notification) obj;
if (details == null) {
if (other.details != null)
return false;
} else if (!details.equals(other.details))
return false;
if (notificationStatusCd == null) {
if (other.notificationStatusCd != null)
return false;
} else if (!notificationStatusCd.equals(other.notificationStatusCd))
return false;
if (notificationUserId == null) {
if (other.notificationUserId != null)
return false;
} else if (!notificationUserId.equals(other.notificationUserId))
return false;
if (updateUserId == null) {
if (other.updateUserId != null)
return false;
} else if (!updateUserId.equals(other.updateUserId))
return false;
return true;
}
}
@Entity
@Table(name="notification_detail")
public class NotificationDetail implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer notificationDetailId;
@NotNull
private Integer notificationTypeCd;
@NotNull
private String notificationMessage;
@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL, mappedBy="details")
private Set<Notification> notifications;
@NotNull
private Integer updateUserId;
public Integer getNotificationDetailId() {
return notificationDetailId;
}
public void setNotificationDetailId(Integer notificationDetailId) {
this.notificationDetailId = notificationDetailId;
}
public Integer getNotificationTypeCd() {
return notificationTypeCd;
}
public void setNotificationTypeCd(Integer notificationTypeCd) {
this.notificationTypeCd = notificationTypeCd;
}
public String getNotificationMessage() {
return notificationMessage;
}
public void setNotificationMessage(String notificationMessage) {
this.notificationMessage = notificationMessage;
}
public Set<Notification> getNotifications() {
return notifications;
}
public void setNotifications(Set<Notification> notifications) {
this.notifications = notifications;
}
public void addNotification(Notification notification){
if(notifications == null)
notifications = new HashSet<Notification>();
notifications.add(notification);
}
public Integer getUpdateUserId() {
return updateUserId;
}
public void setUpdateUserId(Integer updateUserId) {
this.updateUserId = updateUserId;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((notificationDetailId == null) ? 0 : notificationDetailId.hashCode());
result = prime * result + ((notificationMessage == null) ? 0 : notificationMessage.hashCode());
result = prime * result + ((notificationTypeCd == null) ? 0 : notificationTypeCd.hashCode());
result = prime * result + ((notifications == null) ? 0 : notifications.hashCode());
result = prime * result + ((updateUserId == null) ? 0 : updateUserId.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
NotificationDetail other = (NotificationDetail) obj;
if (notificationDetailId == null) {
if (other.notificationDetailId != null)
return false;
} else if (!notificationDetailId.equals(other.notificationDetailId))
return false;
if (notificationMessage == null) {
if (other.notificationMessage != null)
return false;
} else if (!notificationMessage.equals(other.notificationMessage))
return false;
if (notificationTypeCd == null) {
if (other.notificationTypeCd != null)
return false;
} else if (!notificationTypeCd.equals(other.notificationTypeCd))
return false;
if (notifications == null) {
if (other.notifications != null)
return false;
} else if (!notifications.equals(other.notifications))
return false;
if (updateUserId == null) {
if (other.updateUserId != null)
return false;
} else if (!updateUserId.equals(other.updateUserId))
return false;
return true;
}
}
JPA 用法:
NotificationDetail details = new NotificationDetail();
details.setMessage("Hello");
details.setTypeCd(NotificationTypeEnum.INFO);
detail.setUpdateUserId(userId);
Notification notif = new Notification();
notif.setNotifiedUserId(userId);
notif.setStatusCd(NotificationStatusEnum.UNREAD);
notif.setDetails(details);
notificationRepository.save(notif);
***此错误现已解决***:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'notificati0_.details_notificationDetailId' in 'field list'
***原题:***
我已经尝试了所有类型的不同配置。我能想到的最好的是我的情况很复杂,因为父对象 "notification" 有一个复合键 "notification_detail_id" ,它也是子对象的主键。这使得Hibernate很难先持久化child,然后取key保存给parent。
我意识到我的注释某处不正确,但就是想不通。
看起来你正在处理 "derived identity"。将您的 类 更改为如下所示:
class NotificationId implements Serializable {
private static final long serialVersionUID = 1L;
Integer notifiedUserId;
Integer details;
...
}
@Entity
@IdClass(NotificationId.class)
@Table(name="notification")
public class Notification implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@NotNull
@Column(name="notification_user_id")
private Integer notifiedUserId;
@Id
@NotNull
@ManyToOne(fetch=FetchType.LAZY, cascade=CascadeType.ALL)
@JoinColumn(name="notification_detail_id")
private NotificationDetail details;
@NotNull
@Column(name="notification_status_cd")
private Integer statusCd;
@Column(name="update_timestamp")
private Date timestamp;
...
}
注意:
NotificationId.notificationDetailId
已重命名为details
以匹配Notification
中的相应字段
Notification.notificationDetailId
已删除Notification.details
已被标记为@Id
您的字段模型似乎暗示您应该对 Notification
和 User
之间的关系做同样的事情。
派生身份在 JPA 2.1 规范的第 2.4.1 节中进行了讨论。