Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么JPA双重插入子实体?_Java_Jpa_Spring Data Jpa - Fatal编程技术网

Java 为什么JPA双重插入子实体?

Java 为什么JPA双重插入子实体?,java,jpa,spring-data-jpa,Java,Jpa,Spring Data Jpa,我有一对实体,称它们为“Ticket”和“TicketComment” 票证具有以下属性: @OneToMany(mappedBy="ticket", cascade = CascadeType.ALL) @OrderBy("date") private List<TicketComment> comments = new ArrayList<>(); 我认为,我正在使用的代码应该添加一条新注释。但是,它似乎向数据库添加了两次新注释: Ticket ticket = t

我有一对实体,称它们为“Ticket”和“TicketComment”

票证具有以下属性:

@OneToMany(mappedBy="ticket", cascade = CascadeType.ALL)
@OrderBy("date")
private List<TicketComment> comments = new ArrayList<>();
我认为,我正在使用的代码应该添加一条新注释。但是,它似乎向数据库添加了两次新注释:

Ticket ticket = ticketRepo.findOne(id);

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

ticketRepo.save(ticket);
我想我已经能够在没有重复的子实体的情况下成功地使用类似的实体了。。。我可能会错过什么


更新:一个解决办法似乎是:

  • 为“TicketComment”创建另一个JpaRepository
  • 使用
    ticketRepo
    将任何其他更新保存到Ticket,而无需创建/添加注释
  • 创建与票证链接的新注释(
    newComment.setTicket(ticket);
    ),并将其保存为
    ticketCommentRepo
  • 因此,有两种不同的保存,一种只影响父对象,另一种只影响子对象

    我想把它降低到一个单一的保存,但我不确定这是可能的


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

    如果我试图简单地保存添加了新“TicketComment”的父“Ticket”实体,会发生什么情况?我看到在数据库中创建了两个不同的记录,它们具有不同的主键,但具有相同的注释文本和相同或几乎相同的时间戳

    比如说,我贴了一条评论,像“看起来不错”。尽管我在调试器中确认在我的
    ticket.getComments()
    中只显示了一个“lookgood”。。。再次加载票证的详细信息页面后,我看到如下内容:

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

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


    当我查看正在准备的SQL语句的一些调试日志时,我看到为我的TicketComments表调用了两个外观相同的INSERT语句,然后对我的Tickets表进行了一次更新…

    我真的不明白您所说的“将新注释添加到数据库两次”是什么意思。您是否看到两个注册中心具有相同的PK

    如果您希望每个注释在票据集合中出现一次,我认为您应该使用
    Set
    界面,而不是
    List
    。 无论如何,我将解释我对该代码片段的预期行为的了解

    Ticket ticket = ticketRepo.findOne(id);
    TicketComment newComment = new TicketComment();
    
    罚单已经存在了?这并不重要,因为您将
    save()
    it。然后创建一个新的注释

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

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

    ticketRepo.save(ticket);
    

    当您将
    ticket
    传递到
    save()
    方法时,操作将传播到您刚刚添加的
    newComment
    实体。
    newComment
    将被传递到
    saveOrUpdate()
    ,然后与
    ticket
    的关系一起保存,您无需在
    newComment
    中指定
    ticket
    只需删除以下行

    newComment.setTicket(ticket);
    
    这将起作用,因为
    cascade
    将自动将
    ticket
    分配给
    newComment
    ,反之亦然
    您实际上是双重分配的,这可能是重复的原因。

    您可以共享您的TickerPo findOne和save方法吗?这些方法是由Spring Data JPA生成的。之后是否保存newComment?是否使用Hibernate作为JPA提供程序?然后,这是的重复。你被冬眠虫击中了。链接帖子有多个解决方法,包括在将子实体添加到父实体之前保存子实体,使用
    Set
    而不是
    List
    ,等等。关联的所有者方位于TicketComment(@manytone)中,因此无法删除行以保持关系。级联只是传播保存操作。是的,我知道
    TicketComment
    是所有者,但这也使它成为该关系中的子对象,因此当您坚持时,如果
    CascadeType,则父对象的子对象将被坚持。坚持
    CascadeType。所有
    都适用于您所说的子对象“cascade将自动为新成员分配票证”,但cascade不会这样做,因为这是一个双向关联。删除该行违反JPA规范。从概念上讲,一个集合对我来说没有多大意义……首先,决定
    equals()的实现
    很奇怪……从技术上讲,有人/可以/发布两次相同的注释。我让Spring数据JPA为我填充注释时间。另外,这些注释有一个逻辑顺序要应用(注释产生的时间),JPA可以为集合这样做吗?(如中所述,它是否支持使用a而不是常规?如果我理解你所说的。为什么设置有意义?首先是因为它是@manish评论的bug()的一个解决方法(你正在承受它)。其次,由于您表示与
    TicketComment
    表中的字段/列的关联,因此每个
    TicketComment
    可以属于一个
    Ticket.comments
    集合,并且只在其中显示一次(类似于一个集合).List在概念上允许重复对象的外观,但不能用表示法保存这种状态。要清楚,每行
    TicketComment
    都是唯一的注释(有一个id…需要明确的是,表的每一行都是一个唯一的注释。它有唯一的主键来标识它,不管另一行是否有相同的注释文本,它们是不同的。您知道实际情况和适用的内容,但相同的文本并不意味着它是相同的注释。例如,请注意stackoverflow对我的下一个c的作用omment…需要明确的是,表的每一行都是唯一的注释。它有唯一的主键来标识它,
    ticketRepo.save(ticket);
    
    newComment.setTicket(ticket);