Search code examples
jpaeclipselink

JPA OneToMany Only Updates First Time


I am using EclipseLink and I have two basic classes like

@Entity
public class Foo {
  @Id
  @Column(name="FOO_ID)
  private int id;
  
  @Column(name="FOO_NAME")
  private String name;
  
  @OneToMany(mappedBy = "foo")
  private List<Bar> bars;
}

@Entity
public class Bar {
  @Id
  @Column(name="BAR_ID")
  private it id;
  
  @Column(name="BAR_NAME")
  private String name;
  
  @ManyToOne
  @JoinColumn(name="FOO_ID")
  private Foo foo;
}

Then I have some code which essentially does

public void processBar(Foo foo) {
  Bar bar = new Bar();
  bar.setName("Test");
  bar.setFoo(foo);
  entityMgr.persist(bar);
  
  List<Bar> bars = foo.getBars();
  
  for (Bar b : bars) {
    System.out.println("Bar - id : " + b.getId());
    System.out.println("Bar - name : " + b.getName());
  }
}

When I go in to the webapp and call the code (foo is set fine) then I can see the expected output of one child Bar with the id and name I expect.

If I then go into a new session and run the same code then instead of seeing two Bars, I am still seeing the first one (and only the first one) but the Bar record is created in the database and is linked correctly.

If I add the same loop to print out bars prior to creating the new Bar then I always see an empty list both before and after creating bar

Setting fetch = FetchType.EAGER) on the oneToMany gives me the empty set. Merging foo after adding bar doesn't make any difference.

What do I need to get this to be consistent?

Update

I do now have this working by implementing an addBar method in Foo

public void addBar(Bar b) {
  bars.add(b);
}

adding a cascade to the relationship

@OneToMany(mappedBy="foo", cascade = CascadeType.ALL)

then I have replaced the persist of bar with foo.addBar(bar)

and finally added entityMgr.merge(foo)

This is now working as I expected but I still don't understand why the original code didn't work so that question still remains about how that code could work (or whether it has to be done as I have done here)


Solution

  • You are using a bidirectional OneToMany Relation, as such, you are responsible for updating the Java model if you add or remove items from the relations, e.g by providing special setters. For an example, see this blogpost.