簡體   English   中英

在ManyToMany上避免使用Spring Data JPA的多個delete語句

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM