У меня есть некоторые сущности, которые связаны с @ManyToMany
следующим образом (нерелевантные поля, конструкторы и методы удалены для краткости):
@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<Skill> skills;
public void addSkill(Skill skill) {
this.skills.add(requireNonNull(skill));
}
public Set<Skill> 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;
}
}
И в классе обслуживания я обновляю Профиль новыми навыками, такими как:
@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<User> userSupplier, ProfileRequest request) {
Profile profile = profileRepository.findByOwner(userSupplier.get())
.map(updateProfileValues(request))
.orElseGet(() -> makeProfile(userSupplier, request));
Profile save = profileRepository.save(profile);
return save != null ? () -> OperationResult.PROFILE_UPDATED : () -> OperationResult.OPERATION_FAILED;
}
private Function<Profile, Profile> updateProfileValues(ProfileRequest request) {
return profile -> {
updateSkills(request, profile);
return profile;
};
}
private void updateSkills(ProfileRequest request, Profile profile) {
Set<Skill> requestSkills = extractSkillsFromRequest(request).collect(toSet());
requestSkills.forEach(profile::addSkill);
Set<Skill> removedSkills = profile.getSkills().stream()
.filter(skill -> !requestSkills.contains(skill))
.collect(toSet());
removedSkills.forEach(profile::removeSkill);
}
private Stream<Skill> extractSkillsFromRequest(ProfileRequest request) {
if (request.getSkills().isEmpty()) {
return Stream.empty();
}
return request.getSkills().stream()
.filter(s -> !s.isEmpty())
.map(this::findOrSaveSkill)
.distinct();
}
private Skill findOrSaveSkill(String s) {
return skillRepository.findById(s)
.orElseGet(() -> skillRepository.save(Skill.of(s)));
}
}
TL; DR: я получаю новый набор навыков из запроса, и мне нужно добавить те, которых нет в профиле, и удалить те, которых нет в запросе.
При этом способе выполняется один оператор удаления в таблице соединений для каждого навыка, удаляемого из профиля. Каков был бы (чистый) способ объединить это в один оператор удаления?
ПРИМЕЧАНИЕ. Это приложение Spring Boot 1.5.12 с Spring Data JPA 1.11.11