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

标签 mysql hibernate jpa spring-boot spring-data-jpa

这个问题涉及管理 ID 号,以确保我的 table 上不会出现重复的身份。这是一个带有MySQL数据库的springboot项目。

一些背景:

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

“情节”由现场工作人员输入并提交到数据库(db1)中。几个小时后,BackOffice 工作人员将这一集手动输入到第二个数据库 (db2)。

在我的 spring 附加数据库 (db1) 上,我有一个 Person 表,其中有一个 native 自动生成的 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 来合并重复的身份。如果合并后删除了 id,则保存 Episode_id 和 person_id 的连接表也需要更新。

最佳答案

如果将 @ManyToMany 关联替换为 2 个双向 @OneToMany 关联,事情就会容易得多,这意味着您也可以映射关联表。

这样,考虑到您有重复的 EpisodePerson 实体,您只需调整 @ManyToOne 即可轻松移动已连接的关联> 关联实体上的关联。对于重复的EpisodePerson,您可以按照下面的说明使用UPSERT,或者在通过批处理将条目添加到数据库后进行手动合并。

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

您可以将 UPSERT 与 Hibernate 结合起来 @SqlInsert annotation .

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

关于mysql - 如何使用 JPA 和 Hibernate 对新实体的子级执行级联合并,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43670268/

相关文章:

javascript - 如何使用PHP在mysql数据库中动态添加html表数据?

php - Laravel 不等于 x 2

mysql - 如何使用一个 MySQL 查询选择所有带有标签的文章和所有文章的标签?

java - @事务回滚不起作用

java - 如何在hibernate中检查不同id的相同数据是否存在?

java - spring data jpa的奇怪行为

mysql - 在mysql中将字符串转换为24小时日期时间格式

sql-server - 如何在spring jpa实体中提及sqlserver数据库名称?

java - Hibernate @NamedQuery 加入

java - 如何查询数据库中未映射到实体的结果集(JPA、JBoss)