Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA OneToMany - List doesn't update after add/delete object, but is persisted in DB

I'm using JPA not Hibernate. I have a Problem with my Relationship as follows. I have a 1:N Relationship (Parent:Child).

On a JSP-Site, the Parent and the Children are displayed. If I load the JSP-Site (for the first time) and save a Parent with a Child, all is ok. The Parent is saved and the Child is saved too to the DB with the foreign key.

After that, a second JSP-Site is displayed with the Parent and Children.

But if I go back to the first Site and save a second Child (adding Child) to existing Parent, the childEntityList is still the old one, I mean, the new Child is not inside this List, but inserted in the database.

Why the childEntityList is old and doesn't update?

The Parent:

@Entity
@Table(schema = "test", name = "Parent")
@XmlRootElement
@NamedQueries({...})
public class Parent implements Serializable {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY, generator = "A_SEQ")
    @Basic(optional = false)
    @NotNull
    @Column(name = "ID")
    private int id;

    @OneToMany(mappedBy = "p", fetch = FetchType.LAZY, cascade = CascadeType.ALL)
    private List<ChildEntity> childEntityList = new ArrayList<ChildEntity>();
    // ...

    public List<ChildEntity> getChildEntityList() {
        return childEntityList;
    }

    public void setChildEntityList(List<ChildEntity> childEntityList) {
        this.childEntityList = childEntityList;
    }

    public void addChildEntityToParent(ChildEntity c) {
        this.childEntityList.add(c);
        if(c.getParent() != this) {
            c.setParent(this);
        }
    }

    public void removeChildEntityFromParent(ChildEntity c) {
        childEntityList.remove(c);
    }
    // ...
}

The Child:

@Entity
@Table( name = "Child" )
@NamedQueries({...})
public class ChildEntity implements Serializable {
    @Id
    @GeneratedValue( strategy = GenerationType.IDENTITY )
    @Column( name = "CHILD_ID" )
    private Long childId;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "PARENT_ID")
    private Parent p;
    // ...

    public Parent getParent() {
        return p;
    }

    public void setParent(Parent p) {
        this.p= p;
        if(!p.getChildEntityList().contains(this)) {
            p.getChildEntityList().add(this);
        }
    }

Save-Code:

Parent p = new Parent(...);
ChildEntity c = new ChildEntity(...);
p.addChildEntityToParent(c);
childEntityFacade.create(c);

View-Code:

// ...
public doSomething(Parent p) {
    super(p);
}
// ...
List<ChildEntity> cList = p.getChildEntityList();
System.out.print("Size: " + c.size());
// ...

In the View-Code, the size of the childEntityList is every time the same even I add a Child. Only when I restart the server, all Children of the Parent are displayed.

When is the childEntityList in the Parent Class filled? Is it automatically, because of the @OneToMany?

Can someone explain it?

Update: Should I merge the EntityManager every time when I add/remove a Child object from the Parent list or have I do some other things?

like image 639
user1956764 Avatar asked Jan 08 '13 03:01

user1956764


2 Answers

You need to maintain both sides of a bi-directional relationship. See here.

like image 58
James Avatar answered Oct 04 '22 21:10

James


(I'm using JPA not Hibernate!)

I guess you meant that you are not using the Hibernate API.
JPA is only a persistence API specification and, by itself, does nothing.
So, if you're using JPA... you're using something to do the persistence.

JPA delegates the persistence work to a persistence engine such as Hibernate, EclipseLink, OpenJPA or something else.

You can configure your app to use JPA interfaces with a specific persistence provider, or if the app is running in a JEE container, then the JPA implementation should be provided for you: GlassFish (uses OpenJPA), WebLogic (uses EclipseLink), TomEE (uses OpenJPA).

Should i merge the EntityManager every time when i add/remove a Child Object from the Parent List...

You don't merge the EntityManager; you use it to merge the parent entity:

parent = em.merge(parent);

Relating to your question, when you use merge() in this way... (and because the mapping specifies CascadeType.ALL) then upon reloading page ("Site 1") you should get the refreshed parent object with an updated object network containing changes you made prior to merge(parent), including any newly added children.

like image 40
J Slick Avatar answered Oct 04 '22 20:10

J Slick