JPA @onetomany级联插入引发org.hibernate.exception.ConstraintViolationException

时间:2019-01-17 10:28:39

标签: java postgresql hibernate jpa

附件类:

@Entity
@Table(name="attachments")
@Getter
@Setter
public class AttachmentModel {

    //@EmbeddedId
    //private AttachmentId attachmentId;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="notice_attachment_id")    
    private long attachmentId;

    @Column(name="notice_id")
    private long noticeId;

    @Column(name="attachment")
    private String attachmentUrl;

    @JsonIgnore
    @ManyToOne(cascade = {CascadeType.PERSIST , CascadeType.MERGE,
            CascadeType.DETACH , CascadeType.REFRESH},optional = false)
    @JoinColumn(name="notice_id", insertable=false, updatable=false)
    @MapsId("notice_id")
    NoticesModel notice;

    public void addNotice(NoticesModel notice) {
        this.notice = notice;
    }

    public AttachmentModel() {

    }   
}

通知类别:

@Entity
@Table(name = "notices")
@Getter @Setter
public class NoticesModel {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "notice_id" ,updatable = false, nullable = false,insertable = true)
    private long noticeID;

    @OneToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL } , mappedBy = "notice")
    //@mappedBy(name = "notice_id")
    private List<AttachmentModel> attachments;
}

解析并保存JSON的代码

public HashMap<String,Object> saveNotices(@RequestBody List<NoticesModel> tmpNotices)
    {
        List<NoticesModel> notices = tmpNotices;
        for (NoticesModel notice : notices) {
            List<AttachmentModel> attachments =  notice.getAttachments();
            for (AttachmentModel attachment : attachments) {
                attachment.addNotice(notice);
                System.out.println(attachment.getAttachmentUrl());
            }

            for (AttachmentModel attachment : attachments) {
                //attachment.addNotice(notice);
                System.out.println(attachment.getNotice().getContent());
                System.out.println(attachment.getNotice().getNoticeID());
            }
        }
        int result = noticesServices.saveNotice(notices);

        HashMap<String,Object> res = new HashMap<>();
        res.put("message",result);
        return res;

    }

这是我发送的JSON

[
  {
    "attachments": [
      {
        "attachmentUrl": "/abc/bcd"
      }
    ],
    "content": "string",
  }
]

在这种情况下,我尝试保存并保存我的通知和附件。 在这种情况下,保存到数据库时会创建notice_id。

因此,在尝试保存附件表时,它会尝试将notice_id保存为0。

所以我得到了例外。

无法执行语句; SQL [n / a];约束[attachments_notices_fk];嵌套的异常是org.hibernate.exception.ConstraintViolationException:无法执行语句

如何解决此问题? 是否可以在保存到数据库之前获取notice_id,以便我可以获取 notice_id ,以便可以将其设置为附件,从而不会将其保存为0? 在这种情况下(我对JPA和springboot很陌生),我在做什么错(我可以采取的其他替代方法)?

1 个答案:

答案 0 :(得分:1)

我认为您无需使用任何notice_id。从notice_id中删除AttachmentModel和相关内容,并使用notice进行映射(注意:删除后db中仍然会有列notice_id),所以:

@ManyToOne
private NoticesModel notice;

并同时更改NoticesModel中的映射以引用正确的字段:

//                                    ALL is just a suggestion
@OneToMany(mappedBy = "noticesModel", cascade = CascadeType.ALL)
private List<AttachmentModel> attachementModels;

然后您的for循环可能类似于:

for (NoticesModel notice : notices) {
    for (AttachmentModel am : notice.getAttachments()) {
        am.setNotice(notice);
    }
    noticesServices.save(notice);
}

您还可以在NoticesModel中添加类似的内容,以始终在持久化之前处理对引用的设置:

@PrePersist
private void prePersist() {
    for (AttachmentModel am : attachments) {
        am.setNotice(this);
    }
}