【问题标题】:JPA @onetomany cascade insert is throwing org.hibernate.exception.ConstraintViolationExceptionJPA @onetomany 级联插入正在抛出 org.hibernate.exception.ConstraintViolationException
【发布时间】:2019-01-17 10:28:39
【问题描述】:

附件类:

@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 [不适用];约束[attachments_notices_fk];嵌套异常是 org.hibernate.exception.ConstraintViolationException: could not execute statement

我怎样才能解决这个问题? 这是否可以在保存到数据库之前获取notice_id,以便我可以获得notice_id,以便我可以将其设置在附件中,这样它就不会被保存为0? 在这种情况下(我对 JPA 和 springboot 很陌生)我做错了什么(我可以采取的任何替代方法)?

【问题讨论】:

    标签: java postgresql hibernate jpa


    【解决方案1】:

    我认为您不需要使用任何notice_id。从您的AttachmentModel 中删除notice_id 和相关内容并使用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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-11-16
      • 1970-01-01
      • 1970-01-01
      • 2015-07-27
      • 2021-08-30
      • 2017-06-07
      • 2020-01-25
      相关资源
      最近更新 更多