Hello,
I am using the latest version of Hibernate (3.2.1.GA) with JPA annotations.
I've got two classes: Student and Exam. A student only consists of a name and an exam consists of a name and a list of students.
I load an exam from the database and remove a student from the list. When I merge the resulting exam object into the database the student's removal does not get persisted in the database.
In Java-(pseudo)-code it would look like this:
Code:
Exam exam = (Exam) entityManager.createQuery("FROM Exam ex").getSingleResult();
exam.removeStudent(exam.getStudents().get(0)); // Removes the first student
entityManager.merge(exam); <-- This does not persist the changed list.
This is the complete testcase: (The test fails with Firebird and H2 - that's all I've tested as I think it is a general issue)
Exam.java:
Code:
package hibernate;
import java.util.ArrayList;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
@Entity
public class Exam {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
@ManyToMany()
@JoinTable(name = "Exams_Students")
private List<Student> students = new ArrayList<Student>();
public Exam() {
}
public Exam(String name) {
super();
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public List<Student> getStudents() {
return this.students;
}
public void addStudent(Student student) {
this.students.add(student);
}
public void removeStudent(Student student) {
this.students.remove(student);
}
}
Student.java:
Code:
package hibernate;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
public Student() {
}
public Student(String name) {
super();
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
BaseTest.java:
Code:
package hibernate;
import javax.persistence.EntityManagerFactory;
import org.hibernate.ejb.Ejb3Configuration;
import org.junit.Before;
import de.pwell.wvmonitor.domain.Location;
import de.pwell.wvmonitor.domain.Machine;
public class BaseTest {
protected EntityManagerFactory factory;
@Before
public void setUp() {
Ejb3Configuration cfg = new Ejb3Configuration();
cfg.setProperty("hibernate.hbm2ddl.auto", "create");
cfg.setProperty("hibernate.connection.pool_size", "1");
cfg.setProperty("hibernate.current_session_context_class", "thread");
cfg.setProperty("hibernate.cache.provider_class", "org.hibernate.cache.NoCacheProvider");
cfg.setProperty("hibernate.show_sql", "true");
// cfg.setProperty("hibernate.connection.driver_class", "org.firebirdsql.jdbc.FBDriver");
// cfg.setProperty("hibernate.connection.url", "jdbc:firebirdsql:server:/var/lib/firebird2/wvmonitor/wvmonitor.fdb");
// cfg.setProperty("hibernate.connection.username", "sysdba");
// cfg.setProperty("hibernate.connection.password", "master");
// cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.FirebirdDialect");
cfg.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
cfg.setProperty("hibernate.connection.url", "jdbc:h2:mem:");
cfg.setProperty("hibernate.connection.username", "sa");
cfg.setProperty("hibernate.connection.password", "");
cfg.setProperty("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
cfg.addAnnotatedClass(Exam.class);
cfg.addAnnotatedClass(Student.class);
this.factory = cfg.createEntityManagerFactory();
}
}
Test.java:
Code:
package hibernate;
import static org.junit.Assert.fail;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityTransaction;
import javax.persistence.Query;
public class Test extends BaseTest {
/**
* {@inheritDoc}
*/
@Override
public void setUp() {
super.setUp();
EntityManager em = factory.createEntityManager();
EntityTransaction trans = em.getTransaction();
trans.begin();
try {
em.persist(new Student("Peter"));
em.persist(new Student("Mike"));
em.persist(new Student("Steve"));
List<Student> students = (List<Student>) em.createQuery("FROM Student t").getResultList();
Exam ex = new Exam("Exam 1");
int counter = 0;
for (Student student : students) {
ex.addStudent(student);
}
em.persist(ex);
trans.commit();
} finally {
if (trans.isActive())
trans.rollback();
}
}
@org.junit.Test
public void testExam() {
EntityManager em = factory.createEntityManager();
EntityTransaction trans = em.getTransaction();
trans.begin();
try {
Query query = em.createQuery("FROM Exam t");
query.setMaxResults(1);
Exam ex = (Exam)query.getSingleResult();
if (ex.getStudents().size() != 3)
fail("Here should be three students.");
ex.removeStudent(ex.getStudents().get(0));
em.merge(ex);
em.flush();
trans.commit();
} finally {
if (trans.isActive())
trans.rollback();
}
// Create new EntityManager.
em = factory.createEntityManager();
Query query = em.createQuery("FROM Exam t");
query.setMaxResults(1);
Exam updatedEx = (Exam)query.getSingleResult();
if (updatedEx.getStudents().size() != 2)
fail("Here should only be two students."); // <--- Here does the test fail.
}
}
I am doing something wrong or is it a bug in hibernate?
Regards and thanks a lot for helping,
Dominik