[英]Spring Data Jpa - ManyToMany - delete entities of the join table
[英]Avoid multiple delete statements with Spring Data JPA on ManyToMany
我有一些這樣的實體與@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;
}
}
在服務類中,我正在使用以下新技能更新Profile:
@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:我從請求中獲得了一套新的技能,我必須添加配置文件中不存在的技能,並刪除請求中不存在的技能。
通過這種方式,對於從配置文件中刪除的每個技能,都會在聯接表上執行一條delete語句。 將其組合成單個delete語句的(干凈)方法是什么?
注意:這是一個帶有Spring Data JPA 1.11.11的Spring Boot 1.5.12應用程序
當然,問題是我對Hibernate的了解不足。 設置Hibernate的jdbc.batch_size
屬性可以輕松解決此問題。 在Spring Boot的application.properties
添加以下行:
spring.jpa.properties.hibernate.jdbc.batch_size=20
完成后,現在Hibernate最多可以批處理20條語句。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.