I have two entites, Person
and Teacher
, with a OneToMany relationship:
public class Person implements Serializable {
@Id
@Column(nullable = false)
private String login;
@OneToMany(mappedBy = "person")
private List<Teacher> teacherList;
}
public class Teacher implements Serializable {
@ManyToOne
@JoinColumn(name = "LOGIN")
private Person person;
}
I also have a DTO class for Person
:
public class PersonDTO extends Person {
private boolean isTeacher;
public PersonDTO(Person p) {
setLogin(p.getLogin());
isTeacher = getTeacherList().size() > 0;
}
public boolean isTeacher() {
return isTeacher;
}
}
My EJB has code like this for inserting new Teacher
s and reading Person
s:
public void addTeacher(String login, String password, String name,
String dept, String title) {
p = new Person(true, false, login, name, password);
persistEntity(p);
Teacher t = new Teacher(dept, p, title);
persistEntity(t);
em.flush(); // 'em' is the Entity Manager
}
public PersonDTO readPerson(String login) {
Person p = em.find(Person.class, login);
PersonDTO pdto = new PersonDTO(p);
return pdto;
}
On my webpage, there's a table showing all teachers, textboxes for the various fields, and a button to add a new teacher and update the table, the listener for which looks like this:
public void addTeacherListener(ActionEvent actionEvent) {
adminManager.addTeacher(/* parameters */);
// update table (which is bound to 'teacherList')
teacherList = new LinkedList<Teacher>();
List<String> logins = adminManager.findAllPerson();
for (String login : logins) {
PersonDTO pdto = adminManager.readPerson(login);
if (pdto.isTeacher()) {
teacherList.add(pdto.getTeacherList().get(0));
}
}
}
The problem is that after inserting a new Teacher, it doesn't show up in the table. The precise reason for this is that the PersonDTO
object returned by readPerson
has isTeacher
set to false: which means that at the time the DTO object is created (that is, after the insertion operation finished, including the two persists and the flush at the end), the Person
object for the given teacher has an empty teacherList
.
However, if I close the page and relaunch it from the IDE, the newly inserted elements show up in the table. So apparently TopLink does set up the relationship, just not immediately. What exactly is going on, and how can I force it to do it right after the insertion?
JPA doesn't maintain consistent bidirectional relationships between object in memory automatically, it's your own task.
That is, after executing addTeacher()
you have a Teacher
with person
property pointing to the Person
. This relationship is reflected in the database, but it's not reflected in teacherList
of the Person
that is already in memory. em.find()
return the existing instance of Person
from the persistence context, so its teacherList
is iempty.
Therefore you need to add a Teacher
into Person.teacherList
in addTeacher()
.