为什么JPA会双插入子实体?

时间:2015-08-10 20:10:29

标签: java jpa spring-data-jpa

我有一对实体,称之为" Ticket"和#34; TicketComment"。

Ticket有这个属性:

@OneToMany(mappedBy="ticket", cascade = CascadeType.ALL)
@OrderBy("date")
private List<TicketComment> comments = new ArrayList<>();

而且,TicketComment有这个:

@ManyToOne
@JoinColumn(name="TKT_ID")
@NotNull
private Ticket ticket;

我认为,我使用的代码应添加一条新评论。但是,它似乎将新注释添加到数据库两次:

Ticket ticket = ticketRepo.findOne(id);

TicketComment newComment = new TicketComment();
// ...
newComment.setTicket(ticket);
ticket.getComments().add(newComment);

ticketRepo.save(ticket);

我认为在没有重复的子实体之前,我已经能够成功地与类似的实体做到这一点......我可能会缺少什么?

更新:解决方法似乎是:

  1. 为&#34; TicketComment&#34;
  2. 创建另一个JpaRepository
  3. 将任何其他更新保存到故障单,而无需使用ticketRepo创建/添加评论。
  4. 创建新评论,与故障单(newComment.setTicket(ticket);)关联,并使用ticketCommentRepo保存。
  5. 所以,有两个不同的保存,一个应该只影响父母,另一个应该只影响孩子。

    我想把它归结为一次保存,但我不确定是否可能?

    更新2 :澄清观察到的症状。

    如果我试图简单地保存我的父母&#34; Ticket&#34;会发生什么?实体与新的&#34; TicketComment&#34;补充说,我看到在数据库中创建了两个不同的记录,这些记录具有不同的主键,但具有相同的注释文本,以及相同或几乎相同的时间戳。

    因此,举例来说,我发布了一条评论,例如&#34;看起来很好&#34;。即使我在调试器中确认只有一个&#34;看起来很好&#34;显示在我的ticket.getComments() ...我再次加载票证的详细信息页面后,我看到类似的内容:

      

    me @ 2015-09-11 23:16:58:看起来不错

         

    me @ 2015-09-11 23:16:59:看起来不错

    当我查看正在准备的SQL语句的一些调试日志时,我看到为我的TicketComments表调用了两个相同的INSERT语句,然后是我的Tickets表的一个UPDATE ......

2 个答案:

答案 0 :(得分:2)

我真的不明白你的意思“将新评论添加到数据库两次”。您是否看到两个具有相同PK的注册表?

如果您希望每个评论在故障单的集合中出现一次,我认为您应该使用Set界面而不是List 。 无论如何,我将解释我所知道的关于代码片段所期望的行为的部分。

Ticket ticket = ticketRepo.findOne(id);
TicketComment newComment = new TicketComment();

机票已经存在?没关系因为你会save()它。你创建了一个新的评论。

newComment.setTicket(ticket);

这是必要的,因为关联的所有者方在TicketComment实体中,并且保持对象模型一致(在某些情况下可能不需要)。

ticket.getComments().add(newComment);

ticket.comments集合上设置 cascade = ALL 时,ticket上触发的所有操作(保存,更新等)都将传播到所有实体对象在集合中。

ticketRepo.save(ticket);

当您将ticket传递给save()方法时,该操作会传播到您刚刚添加的newComment实体。 newComment将传递给saveOrUpdate(),然后与ticket的关系一起保留。

答案 1 :(得分:0)

您无需在ticket中指定newComment 只需删除以下行

即可
newComment.setTicket(ticket);

这可行,因为cascade会自动将ticket分配给newComment,反之亦然 你实际上是双重分配,这可能是重复的原因。