如何使用JPA和Hibernate对新实体的子进行级联合并

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用JPA和Hibernate对新实体的子进行级联合并相关的知识,希望对你有一定的参考价值。

这个问题与管理身份证号码有关,以确保我不会在我个人的桌子上出现重复身份。它是一个带有mysql数据库的springboot项目。

一些背景:

我有一个用于提交“剧集”的html表单。每集都包含“人物”,并与ManyToMany的“人物”有关系。

“剧集”被现场工作人员输入并提交到数据库(db1)。几个小时后,BackOffice工作人员将该剧集手动输入第二个数据库(db2)。

在我的Spring附加数据库(db1)上,我有一个person表,它有一个本机自动生成的id字段。 db1还有一个id2字段 - 它记录来自db2的人的唯一ID。

现场工作人员在进入剧集时并不总是能够访问id2,但BackOffice的工作人员会这样做。

当我保存一个新的“剧集”时,我需要使用save方法来检查数据库中是否存在person id2并对person执行更新(而不是创建新的)。

然后删除重复的人。

插曲实体:

@Entity
public class Episode {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
@Column(name="start_date")
@DateTimeFormat (pattern="dd/MM/yyyy HH:mm")
private Date start_date;
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@JoinTable(name = "episode_person", joinColumns = @JoinColumn(name = "episode_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "id"))
private List<Person> persons;
@OneToOne(cascade=CascadeType.ALL)
//@JoinColumn(name = "id")
private Address address;

人物实体

@Entity
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long id2;
private String surname;
private String firstname;
private String phoneHome;
@DateTimeFormat(pattern = "dd/mm/yyyy")
private Date dob;
@ManyToMany(mappedBy = "persons", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
private List<Episode> episodes;

EpisodeServiceImpl

@Override
@Transactional
public Episode saveEpisode(Episode episode) {
    List mergedPeople = personService.mergeDetachedWithAttached( episode.getPersons() );
    episode.setPersons( mergedPeople );
    return episodeRepository.save(episode);
}

PersonServiceImpl

    @Transactional
@Override
public List mergeDetachedWithAttached(List<Person> people) {
    final List<Person> results = new ArrayList<>();
    if ( people != null && !people.isEmpty() ) {

        // loop over every person
        for (Person person : people) {

            // for current person try to retrieve from db via Id2
            Person db2Person = personRepository.findById2( person.getId2() );

            // if a person was retrieved use them instead of submitted person
            if (db2Person != null ) {
                System.out.println("A matching person was found in the db using id2 - this is the person that will be added");
                results.add(db2Person);
            } else {
                results.add(person);
            }
        }
    }
    return results;

这是在提交新剧集的那一刻编写的,我创建了新的人,即使我使用id2从db1成功查找并将它们添加到剧集中也是如此。

我该如何处理这个:

我可以根据比较id2合并重复的身份。保存episode_id和person_id的连接表也需要在合并后删除id的位置进行更新。

答案

如果用2个双向@ManyToMany关联替换@OneToMany关联会更容易,这意味着您也映射关联表。

这样,考虑到你有那些重复的EpisodePerson实体,你可以通过简单地调整关联实体上的@ManyToOne关联来轻松移动连接的关联。对于重复的EpisodePerson,您可以使用UPSERT,如下所述,或者在批处理将条目添加到数据库后进行手动合并。

通常,当您有多个并发运行的节点时,可以使用数据库UPSERT或MERGE操作,如本qazxsw poi中所述。

你可以把UPSERT和Hibernate free sample of my book, High-Performance Java Persistence结合起来。

要处理FK更新,您需要使用FK ON DELETE CASCADE策略。

以上是关于如何使用JPA和Hibernate对新实体的子进行级联合并的主要内容,如果未能解决你的问题,请参考以下文章

如何从 @ManyToMany 关系中删除与 JPA 和 Hibernate 中的许多子对象的子对象

如何使用 JPA 和 Hibernate 删除带有 JOIN 的实体

如何使用 JPA 和 Hibernate 连接两个不相关的实体

如何使用 JPA 和 Hibernate 将 MySQL JSON 列映射到 Java 实体属性

如何使用 Spring Data JPA(Hibernate) 跨映射表过滤关联实体?

使用 JPA / Hibernate 在无状态应用程序中进行乐观锁定