*** Solved - Updated w/ the Resolution* **
I have two tables:
notification - composite key made of UserId + NotificationDetail
notification_detail - single primary key
I want to use JPA to persist and read these objects but cannot get the ManyToOne mapping to work.
Many notification map to one notification_detail .
Tables:
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)
);
*** Resolved and Correct JPA Setup: * **
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 Usage:
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);
*** This error is now resolved * **:
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'notificati0_.details_notificationDetailId' in 'field list'
*** Original Problem: * **
I've tried all types of different configurations. The best I can come up with is that my situation is complicated because the parent object "notification" has a composite key "notification_detail_id" that is the primary key of the child as well. This makes it's very difficult for Hibernate to persist the child first, then take the key and save it for the parent.
I realize my annotations are incorrect somewhere but just can't figure it out.
It looks like you are dealing with a "derived identity". Change your classes to look like this:
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;
...
}
NB:
NotificationId.notificationDetailId
has been renamed to details
to match the corresponding field in Notification
Notification.notificationDetailId
has been removed Notification.details
has been marked as an @Id
Your field model seems to imply you should do the same thing with the relation between Notification
and User
.
Derived identities are discussed in the JPA 2.1 spec, section 2.4.1.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.