JPA多对多级联问题

JPA many to many Cascade issue

我有两个实体,我想在删除 child 时从 parent 集中删除 child。 删除函数删除 child 实体,但不会从 ParentChild table.

中删除记录

所以我有以下问题:

2021-01-04 11:31:35.601 ERROR 14264 --- [  XNIO-1 task-2] c.f.timesheet.web.rest.AppUserResource   : Exception in getAppUser() with cause = 'javax.persistence.EntityNotFoundException: Unable to find com.freemind.timesheet.domain.Job with id 3351' and exception = 'Unable to find com.freemind.timesheet.domain.Job with id 3351; nested exception is javax.persistence.EntityNotFoundException: Unable to find com.freemind.timesheet.domain.Job with id 3351'

我也有这个:

2021-01-04 11:31:35.598  WARN 14264 --- [  XNIO-1 task-2] o.h.e.loading.internal.LoadContexts      : HHH000100: Fail-safe cleanup (collections) : org.hibernate.engine.loading.internal.CollectionLoadContext@55a124f7<rs=HikariProxyResultSet@372007568 wrapping org.postgresql.jdbc.PgResultSet@3901bf09>

实体:

工作(child):

@ManyToMany(mappedBy = "jobs", cascade = CascadeType.REFRESH,fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@JsonIgnore
private Set<AppUser> appUsers = new HashSet<>();

...

 public void removeAppUsers() {
        if (this.appUsers.size() > 0) 
            for (AppUser ap : this.appUsers) {
                log.debug("Request to delete Job from User : {}", ap);
                ap.removeJob(this);
                log.debug("Request to delete Job from User : {}", ap);
            }
    }

AppUser(parent):

@ManyToMany(cascade = CascadeType.REFRESH,fetch = FetchType.LAZY)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@JoinTable(
    name = "app_user_job",
    joinColumns = @JoinColumn(name = "internal_user_id"),
    inverseJoinColumns = @JoinColumn(name = "job_id", referencedColumnName = "id")
)
private Set<Job> jobs = new HashSet<>();

...

  public AppUser removeJob(Job job) {
        this.jobs.remove(job);
        job.getAppUsers().remove(this);
        return this;
    }

服务(@Service,@Transactionnal):

public void delete(Long id) {
    log.debug("Request to delete Job : {}", id);
    Job j=jobRepository.getOne(id);
    j.removeAppUsers();
    jobRepository.deleteById(id);
}

我做错了什么? 谢谢

我使用下面显示的代码对此进行了测试。问题似乎是您没有保存 AppUser 实例。

AppUserclass

package no.mycompany.myapp.misc;

import lombok.Data;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Data
@Entity
public class AppUser {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToMany
    @JoinTable(
            name = "app_user_job",
            joinColumns = @JoinColumn(name = "internal_user_id"),
            inverseJoinColumns = @JoinColumn(name = "job_id", referencedColumnName = "id")
    )
    private Set<Job> jobs = new HashSet<>();

    Job addJob(Job job) {
        job.getAppUsers().add(this);
        this.jobs.add(job);
        return job;
    }

    void removeJob(Job job) {
        this.jobs.remove(job);
    }
}

应用程序用户库

package no.mycompany.myapp.misc;

import org.springframework.data.jpa.repository.JpaRepository;

public interface AppUserRepo extends JpaRepository<AppUser, Long> {}

工作class

package no.mycompany.myapp.misc;

import lombok.Getter;
import lombok.Setter;

import javax.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Getter
@Setter
@Entity
public class Job {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToMany(mappedBy = "jobs")
    private Set<AppUser> appUsers = new HashSet<>();
}

工作回购

package no.mycompany.myapp.misc;

import org.springframework.data.jpa.repository.JpaRepository;

public interface JobRepo extends JpaRepository<Job, Long> {}

测试

package no.mycompany.myapp.misc;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.context.ActiveProfiles;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

@DataJpaTest
public class AppUserRepoTest {

    @Autowired
    TestEntityManager testEntityManager;

    @Autowired
    AppUserRepo appUserRepo;

    @Autowired
    JobRepo jobRepo;

    @Test
    public void test() {

        var appUser = testEntityManager.persist(createValidAppUser());

        var job1 = testEntityManager.persist(createValidJob());
        var job2 = testEntityManager.persist(createValidJob());
        var job3 = testEntityManager.persist(createValidJob());

        var appUserInDb = appUserRepo.getOne(appUser.getId());

        // add 3 jobs to AppUser instance
        var job1InDb = appUserInDb.addJob(jobRepo.getOne(job1.getId()));
        var job2InDb = appUserInDb.addJob(jobRepo.getOne(job2.getId()));
        appUserInDb.addJob(jobRepo.getOne(job3.getId()));
        appUserRepo.save(appUserInDb);

        // verify that AppUser instance has 3 jobs
        appUser = testEntityManager.find(AppUser.class, appUser.getId());
        assertThat(appUser.getJobs().size()).isEqualTo(3);

        // verify that job #1 instance has 1 AppUser instance
        job1 = testEntityManager.find(Job.class, job1.getId());
        assertThat(job1.getAppUsers().size()).isEqualTo(1);

        // remove 2 jobs from AppUser instance
        appUserInDb = appUserRepo.getOne(appUser.getId());
        appUserInDb.removeJob(job1InDb);
        jobRepo.delete(job1InDb);

        appUserInDb.removeJob(job2InDb);
        jobRepo.delete(job2InDb);

        appUserRepo.save(appUserInDb);

        // verify that AppUser instance has 1 job
        appUser = testEntityManager.find(AppUser.class, appUser.getId());
        assertThat(appUser.getJobs().size()).isEqualTo(1);

        // verify that job instances are deleted in db
        assertThat(testEntityManager.find(Job.class, job1.getId())).isNull();
        assertThat(testEntityManager.find(Job.class, job2.getId())).isNull();
    }

    private static AppUser createValidAppUser() {
        return new AppUser();
    }

    private static Job createValidJob() {
        return new Job();
    }
}