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();
}
}
我有两个实体,我想在删除 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();
}
}