简体   繁体   English

JPA / Hibernate复合主前键ManyToOne映射

[英]JPA/Hibernate Composite Primary Foriegn Key ManyToOne Mapping

*** Solved - Updated w/ the Resolution* ** *** 解决-更新了分辨率* **

I have two tables: 我有两个表:

notification - composite key made of UserId + NotificationDetail notification-由UserId + NotificationDetail组成的复合键

notification_detail - single primary key notification_detail-单主键

I want to use JPA to persist and read these objects but cannot get the ManyToOne mapping to work. 我想使用JPA保留并读取这些对象,但是无法使ManyToOne映射起作用。

Many notification map to one notification_detail . 许多通知映射到一个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: * ** *** 已解决和正确的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 Usage: 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);

*** 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. 我能想到的最好的事情是我的情况很复杂,因为父对象“ notification”有一个复合键“ notification_detail_id”,它也是孩子的主键。 This makes it's very difficult for Hibernate to persist the child first, then take the key and save it for the parent. 这使得Hibernate很难先持久保留子项,然后再获取密钥并将其保存给父项。

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 NotificationId.notificationDetailId已重命名为details以匹配Notification中的相应字段
  • Notification.notificationDetailId has been removed Notification.notificationDetailId已被删除
  • Notification.details has been marked as an @Id Notification.details已被标记为@Id

Your field model seems to imply you should do the same thing with the relation between Notification and User . 您的字段模型似乎暗示您应该对NotificationUser之间的关系执行相同的User

Derived identities are discussed in the JPA 2.1 spec, section 2.4.1. JPA 2.1规范的第2.4.1节中讨论了派生身份。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM