首页 文章

Spring JPA从新的子实体合并父实体

提问于
浏览
1

我搜索了SO并没有为此找到合适的解决方案 . 假设我有一个父实体:

@Entity
public class Parent {
    @Id
    @GeneratedValue
    private int id;

    @OneToMany(mappedBy = "parent", cascade = CascadeType.REMOVE)
    private List<Child> childList;
}

和子实体,它具有与父实体关联的外键:

@Entity
public class Child {
    @Id
    @GeneratedValue
    private int id;

    @JoinColumn(name = "parentId")
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Parent parent;

}

我的场景有点特别 . 子实体每小时生成一次,我需要将它们保存到数据库中 . 这些子对象可以具有相同的父对象,并且关联父实体可能已经存在于数据库中 . 我的要求是保存所有这些子对象,而不从entityManager中查询托管父实体,如果父实体存在,只需合并/更新现有实体 . 如:

Child c = new Child();
// set some properties of child
Parent p = new Parent();
// set some properties from my data into the parent. The parent may already exists
child.setParent(p);
JpaRepo.saveAndFlush(child);// If parent already exists, merge with the existed parent object, otherwise, create new parent object.

显然这不起作用 . 当父实体不存在时,它将正确创建父实体并与之关联 . 但是如果父项已经存在,它将抛出关于重复键的异常,如果我设置了父项的Id(使用虚拟值强制使其通过合并),它将抛出分离的实体对象的异常 .

由于性能限制,我无法从数据库加载父实体,因为它们太多了 . 那么当主键违反时,有没有办法自动为JPA或数据库合并对象?

我正在使用MySQL,是否可以使用ON DUPLICATE KEY UPDATE?

1 回答

  • 0

    你想要实现的是一个有点棘手的工作人员 . 如果延迟加载等不是一个选项(我更喜欢),我建议您创建另一个实体:

    @Entity
    @Table(name = "sameAsTheOriginal")
    public class ChildSaveObject {
        @Id
        @GeneratedValue
        private int id; //I think int will run out fast if there are a lot of objects but it is your choice. (Int max value: 2 147 483 647 is not that mutch) I prefer Long az id
    
        @Column(name = "parentId")
        private int parent; //note that You need to have the id of the parent object
    
        //Other properties...
    }
    

    在此流程中,您必须检查父对象是否存在,并使用ChildSaveObject将其他子项保存到该对象中 .

    在大多数情况下,我并不喜欢一对多的映射,我认为它们只是很多问题的根源 . 如果您更喜欢这种方式,我的建议是使用 fetch = FetchType.LAZY 并获取父实体(这样它就不会加载您不需要的所有子项) .

相关问题