Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update OneToMany list after entity save in Hibernate

i have relationship:

// In A.java class
@OneToMany(mappedBy="a", fetch=FetchType.LAZY)
@Cascade(CascadeType.SAVE_UPDATE)
private List<B> bList;

// In B.java class
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(name="id_a")
@Cascade(CascadeType.SAVE_UPDATE)
private A a;

Now look this:

A a=new A();
// setting A

B b=new B();
// setting B
b.setA(a);

session.save(b); // this save b and a obviously

Now the "problem":

  • a.getId() -> current new id OK
  • a.getBList() -> still null...

So, why bList is not update in this case?

I tried to reload a after save, in this way:

A a=new A();
// setting A

B b=new B();
// setting B
b.setA(a);

session.save(b);

A loadedA=(A)session.get(A, a.getId());

But loadedA still have a NULL bList like a.

Naturally to avoid this problem i do in thy way:

A a=new A();
// setting A

B b=new B();
// setting B

List<B> bList=new ArrayList<B>();
bList.add(b);
a.setBList(bList);

session.save(a); // this save a and b

In this way all work good, but my question is: Why Id is correctly update after save operation and bList no? I have to query db with a select statement to reload A instance correctly?


UPDATE

I have this exception

StaleStateException: Batch update returned unexpected row count from update

when i try to saveOrUpdate entity a after deleting b from it.

// first delete old b record
Session session=HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
a.getBList().remove(b);
b.setA(null);
session.delete(b);
// session.clear(); // this would solve my problem, but is it correct??
session.getTransaction().commit();

// then insert new b record
Session session=HibernateUtil.getSessionFactory().getCurrentSession();
session.beginTransaction();
B b=new B();
a.getBList().add(b);
b.setA(a);
session.saveOrUpdate(a);   
session.getTransaction().commit(); // this throw exception

this two operation are not in the same method of course, are fired by gui event.

session.clear is the real solution? Im doing (probably) wrong?

update

removing session.delete(b) the problem is solved again... so, what is the corretc way? I know...im totally noob with hibernate..

like image 935
blow Avatar asked Jun 19 '10 18:06

blow


2 Answers

When working with bi-directional associations, you have to set the link on both sides of the association:

A a = new A();
B b = new B();
a.getBList().add(b);
b.setA(a);

session.persist(b);

And actually, the common pattern is to implement defensive link management methods like this:

public class A {

    @OneToMany(mappedBy="a", fetch=FetchType.LAZY)
    @Cascade(CascadeType.SAVE_UPDATE)
    private List<B> bList = new ArrayList<B>();

    protected List<B> getListB() {
        return bList;
    }

    protected void setListB(List bList) {
        this.bList = bList;
    }

    public void addBToBs(B b) {
        bList.add(b);
        b.setA(this);
    }

    //...
}

And the code becomes:

A a = new A();
B b = new B();
a.addBToBs(b);

session.persist(b);

This is discussed in the Hibernate Tutorial:

  • 1.2.6. Working bi-directional links
like image 156
Pascal Thivent Avatar answered Nov 03 '22 01:11

Pascal Thivent


Oh... ok

session.refresh(a);

This work good... is this the solution, isn't true?

like image 21
blow Avatar answered Nov 02 '22 23:11

blow