Reputation: 73
I have two entities and I want to remove the child from the parent set when the child is deleting. The delete function deletes the child entity but it doesn't remove the record from the ParentChild table.
So I have the following issue:
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'
And I also have this one:
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>
Entities:
Job (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;
}
the service (@Service, @Transactionnal):
public void delete(Long id) {
log.debug("Request to delete Job : {}", id);
Job j=jobRepository.getOne(id);
j.removeAppUsers();
jobRepository.deleteById(id);
}
What Am I doing wrong? Thank you
Upvotes: 0
Views: 552
Reputation: 11319
I tested this using code shown below. Problem seems to be that you are not saving the AppUser instance.
AppUser class
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);
}
}
AppUser repo
package no.mycompany.myapp.misc;
import org.springframework.data.jpa.repository.JpaRepository;
public interface AppUserRepo extends JpaRepository<AppUser, Long> {}
Job 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<>();
}
Job repo
package no.mycompany.myapp.misc;
import org.springframework.data.jpa.repository.JpaRepository;
public interface JobRepo extends JpaRepository<Job, Long> {}
Tests
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();
}
}
Upvotes: 3