合并操作如何与一对多关系一起工作 - JPA

时间:2017-02-12 15:29:27

标签: mysql hibernate jpa entitymanager

在我的申请中,我有一个投标实体。

    @Entity
    @Table(name = "tender")
    public class Tender {

        @Id
        @Column(name = "tender_id", unique = true, nullable = false)
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private long id;

        @Column(name = "name")
        private String name;

        @Column(name = "description")
        private String description;

        @OneToMany(mappedBy="tender", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
        @JsonIgnoreProperties("tender")
        private List<TenderAddress> addresses;

        // constructors and getters and setters
        // I am showing the setter for Address since it is customized for my requirement

        public void setAddresses(List<TenderAddress> addresses) {
          this.addresses = addresses;
          for (TenderAddress tenderAddress : addresses) {
            tenderAddress.setTender(this);
          }
        }

    }

我的TenderAddress实体看起来像这样。

@Entity
@Table(name = "tender_address")
public class TenderAddress {

    @Id
    @Column(name = "id", unique = true, nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="tender_id")
    @JsonIgnoreProperties("addresses")
    private Tender tender;

    @Column(name = "address", nullable = false)
    private String address;

    // constructors
    //getters and setters
}

在我开始测试更新操作之前,一切正常。

这是我的更新方法。

@Transactional
    public Tender updateTender(Tender tender) {
        Tender t = entityManager.find(Tender.class, tender.getId());

        t.setName(tender.getName());
        t.setDescription(tender.getDescription());

        t.setAddresses(tender.getAddresses());

        entityManager.merge(t);
        entityManager.flush();
        return findById(t.getId());
    }

名称和说明已更新。我认为地址将如何更新,它将编辑相关数据库表中的当前记录。但是发生的事情是,它在表中插入了一条新记录而没有编辑已经存在的记录。事实上,我认为JPA会照顾自己。

所以,我现在的问题是,合并投标表时是否必须明确合并地址表?如果是这样,应该怎么做?

1 个答案:

答案 0 :(得分:1)

要问的一个问题是,是否还有其他事情与TenderAddress有关联?

如果您的问题的答案是,那么您必须根据某些自然键而不是数据库标识符对列表进行迭代更新。这是因为您的传入列表可能是新条目和更新条目的组合,应该以特定方式合并。

  • 迭代新列表
    • 对于在旧列表中找不到的任何新列表项,请将其添加到旧列表中。
    • 对于在旧列表中找到的任何新列表项,请更新其属性。
  • 迭代旧列表
    • 对于在新列表中找不到的任何旧列表项,请将其删除。

如果您的问题的答案是,那么您可以重新修改映射的注释并完成您认为可行的工作。我们不应将TenderAddress视为实体类型,而是将其更改为@Embeddable并将其置于@ElementCollection内,如下所示:

@Entity
public class Tender {
  @ElementCollection
  private Set<TenderAddress> addresses;
}

@Embeddable
public class TenderAddress {
}

在这种情况下,您现在可以安全地替换TenderAddress的整个集合,Hibernate将基本上根据Tender主键从集合表执行批量删除,然后重新插入所有新的新列表中的行,这些行将与您在问题中提供的代码一起使用。