我有一对实体,称之为" 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);
我认为在没有重复的子实体之前,我已经能够成功地与类似的实体做到这一点......我可能会缺少什么?
更新:解决方法似乎是:
ticketRepo
创建/添加评论。newComment.setTicket(ticket);
)关联,并使用ticketCommentRepo
保存。所以,有两个不同的保存,一个应该只影响父母,另一个应该只影响孩子。
我想把它归结为一次保存,但我不确定是否可能?
更新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 ......
答案 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
,反之亦然
你实际上是双重分配,这可能是重复的原因。