title: Spring Data REST/JPA - Update OneToMany collection with composite key
body: <p>Using Spring Data REST and Spring Data JPA, I want to update a child entity collection on an aggregate root. As an example to demonstrate, let's say I have a <code>Post</code> entity that has a one-to-many relationship with the <code>Comment</code> entity. <code>Post</code> has its own Spring Data repository; <code>Comment</code> does not because it is only accessed through <code>Post</code>.</p>
  
  <p>The nasty twist is that <code>Comment</code> has a composite key including the foreign key to <code>Post</code> due to existing database design. Consequently, I could not find a way to have the foreign key be part of the composite key in <code>Comment</code> without a bidirectional relationship, even though I have no need for a bidirectional relationship.</p>
  
  <p>The classes look like the following with Lombok annotations:</p>
  
  <pre><code>@Entity
  @Data
  public class Post {
  
      @Id
      @GeneratedValue
      private long id;
  
      @OneToMany(mappedBy = "post", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval = true)
      private Set&lt;Comment&gt; comments = new HashSet&lt;&gt;();
  
      private String title;
  }
  </code></pre>
  
  <p>And the Comment:</p>
  
  <pre><code>@Entity
  @IdClass(Comment.CommentPk.class)
  @Data
  @EqualsAndHashCode(exclude = "post")
  @ToString(exclude = "post")
  public class Comment {
  
      @Id
      private long id;
  
      @Id
      @ManyToOne(fetch = FetchType.LAZY)
      @RestResource(exported = false)
      @JsonIgnore
      private Post post;
  
      private String content;
  
      @Data
      static class CommentPk implements Serializable {
          private long id;
  
          private Post post;
      }
  }
  </code></pre>
  
  <p>And the repository:</p>
  
  <pre><code>public interface PostRepository extends JpaRepository&lt;Post, Long&gt; {
  }
  </code></pre>
  
  <p>If I try to create a <code>Post</code> with a <code>Comment</code>, an exception will occur that <code>POST_ID</code> cannot be NULL. In other words, it is missing the back-reference to the parent <code>Post</code> in the <code>Comment</code> it is trying to persist.</p>
  
  <p>This can be solved by adding a <code>@PrePersist</code> method to <code>Post</code> that maintains this back-reference:</p>
  
  <pre><code>@PrePersist
  private void maintainParentBackreference() {
      for (Comment comment : this.comments) {
          comment.setPost(this);
      }
  }
  </code></pre>
  
  <p>The above works fine when creating a new <code>Post</code>, but it does not help when trying to add a <code>Comment</code> to an existing <code>Post</code> (e.g. with a PUT request) because the following error will occur when trying to insert the Comment:</p>
  
  <pre><code>NULL not allowed for column "POST_ID"; SQL statement:
  insert into comment (content, id, post_id) values (?, ?, ?) [23502-193]
  </code></pre>
  
  <p>To recap, the steps to reproduce are:</p>
  
  <ol>
  <li>POST a <code>Post</code> with no <code>Comment</code>s</li>
  <li>PUT to the created <code>Post</code> <strong>with</strong> a <code>Comment</code></li>
  </ol>
  
  <p>What is the simplest way I can achieve being able to update/add <code>Comment</code>s to an existing <code>Post</code> using Spring Data REST?</p>
  
  <p>A sample project that demonstrates this can be found here: <a href="https://github.com/shakuzen/aggregate-child-update-sample/tree/composite-key" rel="nofollow noreferrer">https://github.com/shakuzen/aggregate-child-update-sample/tree/composite-key</a></p>
  
  <p>This particular setup is in the <code>composite-key</code> branch of the repository. To reproduce the above described failure with this code, you can follow the manual reproduction steps in the README or run the integration test <code>AggregateCompositeKeyUpdateTests.canAddCommentWithPut</code></p>