Lukas Risko
Lukas Risko

Reputation: 1489

Hibernate duplicates elements in parent collection while it is populating with newly persisted childs

Can somebody explain the following strange behaviour I encountered? I am trying to persist some new child objects and simultaneously add them to to the parent collection. At the end there are twice as many elements in parent collection as I expected. Let me show the example:

@Entity
public class A {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Integer id;

    @OneToMany(mappedBy = "a")
    private List<B> bs = new ArrayList<>();

    public Integer getId() { return id; }

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

    public List<B> getBs() { return bs; }

    public void setBs(List<B> bs) { this.bs = bs; }
}

@Entity
public class B {

    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Id
    private Integer id;

    @ManyToOne
    private A a;

    public Integer getId() { return id; }

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

    public A getA() { return a; }

    public void setA(A a) { this.a = a; }
}

Test case:

@Test
public void test() throws Exception {
    entityManager.getTransaction().begin();

    A a = new A();

    entityManager.persist(a);
    entityManager.flush();
    entityManager.clear();

    a = entityManager.find(A.class, a.getId());

    for (int i = 0; i < 3; i++) {
        B b = new B();
        b.setA(a);
        entityManager.persist(b);
        a.getBs().add(b);
    }

    assertEquals(3, a.getBs().size());

    entityManager.getTransaction().commit();
}

Result:

java.lang.AssertionError: 
Expected :3
Actual   :6

I don't ask how to modify given code to achieve expected result. I want to understand why given code behaves like this.


Update: Works fine with EclipseLink and DataNucleus, but fails with Hibernate.

Thanks to @riskop answer and my further investigation we can summarize:

Upvotes: 1

Views: 125

Answers (2)

riskop
riskop

Reputation: 1787

Unfortunately I can't tell you exactly how this happening

But I would say that this is a Hibernate bug. It should return 3.

I checked this with Hibernate 5.0.3.Final and experienced the same problem. Then I checked the exact same code with DataNucleus 4.1.9 and that works as expected (no duplicate size of the collection).

However, even with Hibernate the problem goes away if you do any of the following:

  • NOT using @GeneratedValue(strategy = GenerationType.IDENTITY). GenerationType.IDENTITY is discouraged, and can be source of other problems (just google for it). If you change it to auto, then Hibernate works OK.
  • change to Eager fetching on entity A ( @OneToMany(mappedBy = "a", fetch=FetchType.EAGER)
  • initializes the collection on A after loading it from the database (via calling a.getBs().size() for example).

Upvotes: 1

Andrew Michael Felsher
Andrew Michael Felsher

Reputation: 183

I'm not terribly familiar with either Hibernate or Spring, but should

entityManager.flush();
entityManager.clear();

be called after

entityManager.persist(b);

(possibly in addition to where you already have it)

Upvotes: 0

Related Questions