Spring JPA合并来自新子实体

时间:2016-07-18 05:22:23

标签: java spring hibernate spring-data-jpa

我搜索了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 :(得分: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 并获取父实体(这样它就不会加载您不需要的所有子项)。