Search code examples
jpaeclipselinkentitymanagerjta

JavaEE JPA synchronise object with database


I've got a User class and an Email class. I used the @OneToMany annotatioin to describe a realationship that one user can have many emails and one email is assigned to one user.

Now the problem is: when creating a user and an email and assigning the email to the user, I try to find a way that the Set of emails is getting initialized by JPA. Usually this works fine when I am doing em.find(User.class, "test"); This only does not work when I'm creating a user. The emails attribute is always of size 0 or even null. But when I create a user, then redeploy my application and then execute em.find(User.class, "test"), the emails attribute is set correctly of size 1 and I can access it.

@Entity
public class User implements Serializable {
    private String username;
    private String password;
    private Set<Email> emails;

    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
    public Set<Email> getEmails() {
        return emails;
    }

    public void setEmails(Set<Email> emails) {
        this.emails = emails;
    }

    @Id
    @Column(name = "Username")
    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    @Basic
    @Column(name = "Password")
    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

-

@Entity
public class Email implements Serializable {
    private int id;
    private String email;
    private User user;

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "Id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @ManyToOne
    @JoinColumn(name = "user")
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Basic
    @Column(name = "Email")
    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

-

User user = new User();
user.setUsername("test");
user.setPassword("asdf");
em.persist(user);

Email e = new Email();
e.setEmail("[email protected]");
e.setUser(user);
em.persist(e);

return user;

after executing these statements, the user attribute emails is null (obviously). But strangely when I do em.find(User.class, "test"); in another method, the emails attribute is of size 0, even though the records are correctly inserted to the database. When I now redeploy my application and call em.find(User.class, "test"); again, the emails attribute is of size 1. I've already tried to call em.merge(); or em.refresh(); which did not work. I am using glassfish 4.1.1. As transaction-type I use JTA and eclipselink for the JPA implementation


Solution

  • You need to add the email to the User as well and merge the user if you are doing it in two steps, or (you may need cascade=CascadeType.ALL) just put it in the User to begin with and persist the User if you are doing it in one step.

    User user = new User();
    Set<Email> emails = new HashSet<Email>();
    user.setEmails(emails);
    user.setUsername("test");
    user.setPassword("asdf");
    
    Email e = new Email();
    e.setEmail("[email protected]");
    e.setUser(user);
    
    emails.add(e);
    em.persist(user);
    
    return user;