Initial data. Specialty has many subjects.
Specialty.java
@Entity
@Table(name = "specialties")
public class Specialty implements Serializable {
private Long id;
private Set<Subject> subjects;
@Id
@GeneratedValue
@Column(name = "specialty_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@OneToMany(mappedBy = "specialty")
@Cascade(CascadeType.ALL)
public Set<Subject> getSubjects() {
return subjects;
}
public void setSubjects(Set<Subject> subjects) {
this.subjects = subjects;
}
public void addSubject(Subject subject) {
addSubject(subject, true);
}
public void addSubject(Subject subject, boolean set) {
if (subject != null) {
getSubjects().add(subject);
if (set) {
subject.setSpecialty(this, false);
}
}
}
public void removeSubject(Subject subject) {
getSubjects().remove(subject);
subject.setSpecialty(null);
}
}
A specialty can't be null for a subject. I want it works next way: when I save/update/detach a subject the same actions have to be applied to a specialty. When I delete a subject nothing happens with a specialty.
Subject.java
@Entity
@Table(name = "subjects")
public class Subject implements Serializable {
private Long id;
private Specialty specialty;
@Id
@GeneratedValue
@Column(name = "subject_id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@ManyToOne
@JoinColumn(name = "specialty_id")
@Cascade({CascadeType.PERSIST, CascadeType.MERGE, CascadeType.DETACH})
public Specialty getSpecialty() {
return specialty;
}
public void setSpecialty(Specialty specialty) {
setSpecialty(specialty, true);
}
public void setSpecialty(Specialty specialty, boolean add) {
this.specialty = specialty;
if (specialty != null && add) {
specialty.addSubject(this, false);
}
}
}
I write an integration tests. generateSpecialty() and generateSubject() it's just the util methods.
@Before
public void initEntitities() {
specialty = generateSpecialty();
subject = generateSubject();
subject.setSpecialty(specialty);
subjectRepository.save(subject);
entityManager.detach(subject);
}
@Test
public void testSaveSpecialtyViolate2of3UniqueField() {
Subject subject1 = new Subject();
subject1.setSemester(1);
subject1.setUkrName("Тест матан UPD");
subject1.setEngName("XXX");
subject1.setCode("MT 23.O8");
subject1.setCredit(6F);
subject1.setSpecialty(specialty);
subjectService.save(subject1);
assertNotNull(subjectRepository.findOne(subject.getId()));
assertNotEquals(subject.getUkrName(), subject1.getUkrName());
assertEquals(subject.getSemester(), subject1.getSemester());
assertEquals(subject.getSpecialty().getId(),
subject1.getSpecialty().getId());
}
You can see the result of the test on this image.
Exception had been thrown here subjectService.save(subject1);
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: diploma.entity.Specialty
In start of the test the specialty is detached (you can see it on the image. I use entityManager.contains(specialty) to check it). I think the problem is in next: when Hibernate try to save the subject1 it firstly select the specialty from the db and the specialty changes its state to pesist. Do you have any ideas how could I fix it and why it happens?
I had applied the first advice from this link but it didn't help me