title: Avoid multiple delete statements with Spring Data JPA on ManyToMany
body: <p>I have some entities that are related with a <code>@ManyToMany</code> like this (irrelevant fields, constructors and methods removed for brevity):</p>
  
  <pre><code>@Entity
  public class Profile {
      @Id
      @GeneratedValue
      private Long id;
  
      @ManyToMany(cascade = {
          CascadeType.PERSIST,
          CascadeType.MERGE
      })
      @JoinTable(
          name = "profile_skills",
          joinColumns = @JoinColumn(name = "profile_id", referencedColumnName = "id"),
          inverseJoinColumns = @JoinColumn(name = "skill_id", referencedColumnName = "id")
      )
      private Set&lt;Skill&gt; skills;
  
      public void addSkill(Skill skill) {
          this.skills.add(requireNonNull(skill));
      }
  
      public Set&lt;Skill&gt; getSkills() {
          return unmodifiableSet(skills);
      }
  
      public void removeSkill(Skill skill) {
          this.skills.remove(skill);
      }
  }
  
  @Entity
  @EqualsAndHashCode
  public class Skill {
      @Id
      private String id;
      @Column(nullable = false)
      private String name;
  
      public String getId() {
          return id;
      }
  }
  </code></pre>
  
  <p>And in a service class I'm updating Profile with new Skills like this:</p>
  
  <pre><code>@Service
  @Transactional
  public class ProfileUpdaterService implements ProfileUpdater {
      private final ProfileRepository profileRepository;
      private final SkillRepository skillRepository;
  
      ProfileUpdaterService(ProfileRepository profileRepository, SkillRepository skillRepository) {
          this.profileRepository = profileRepository;
          this.skillRepository = skillRepository;
      }
  
      @Override
      public WebResponse updateData(Supplier&lt;User&gt; userSupplier, ProfileRequest request) {
          Profile profile = profileRepository.findByOwner(userSupplier.get())
              .map(updateProfileValues(request))
              .orElseGet(() -&gt; makeProfile(userSupplier, request));
          Profile save = profileRepository.save(profile);
          return save != null ? () -&gt; OperationResult.PROFILE_UPDATED : () -&gt; OperationResult.OPERATION_FAILED;
      }
  
      private Function&lt;Profile, Profile&gt; updateProfileValues(ProfileRequest request) {
          return profile -&gt; {
              updateSkills(request, profile);
              return profile;
          };
      }
  
      private void updateSkills(ProfileRequest request, Profile profile) {
          Set&lt;Skill&gt; requestSkills = extractSkillsFromRequest(request).collect(toSet());
          requestSkills.forEach(profile::addSkill);
          Set&lt;Skill&gt; removedSkills = profile.getSkills().stream()
              .filter(skill -&gt; !requestSkills.contains(skill))
              .collect(toSet());
          removedSkills.forEach(profile::removeSkill);
      }
  
      private Stream&lt;Skill&gt; extractSkillsFromRequest(ProfileRequest request) {
          if (request.getSkills().isEmpty()) {
              return Stream.empty();
          }
          return request.getSkills().stream()
              .filter(s -&gt; !s.isEmpty())
              .map(this::findOrSaveSkill)
              .distinct();
      }
  
      private Skill findOrSaveSkill(String s) {
          return skillRepository.findById(s)
              .orElseGet(() -&gt; skillRepository.save(Skill.of(s)));
      }
  }
  </code></pre>
  
  <p>TL;DR: I get a new set of Skills from a request and I have to add the ones that are not present in the Profile and delete the ones not present in the request.</p>
  
  <p>This way of doing it performs one delete statement on the join table for each skill that is removed from the Profile. What would be a (clean) way to combine this into a single delete statement?</p>
  
  <p>NOTE: This is a Spring Boot 1.5.12 app with Spring Data JPA 1.11.11</p>