Sha Ken
Sha Ken

Reputation: 23

hibernate many-to-many mapping with null set

I have following scenario: Table A and table B has Many-to-Many relationship. Class A is mapped to table A and Class B is Mapped to Table B and there is a Join table AB. Class A has Set of class B and Class B has Set of class A. I have Three different user interfaces to Create/Update A, B and AB. When I load A's information in A's UI I dont want to load list of B with that (performance reasons). So while saving A, I get only information related to A and Set is null. When I save this instance of A it deletes all existing mappings between A and B. Does hibernate allow such save? or do we always have to populate Set before saving A?


Database table A:

aid | data
---------

Database table B:

bid | data
---------

Database table AB:

aid | bid
----------

Class A{
    private long aid;
    private String data;
    private Set<B> bSet;
}

Class B{
    private long bid;
    private String data;
    private Set<A> aSet;
}


<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name='test.A' table='A'>
        <id name='aid' type='long' column='aid'>
        </id>
        <set name="bSet" table="AB"
            inverse="false" fetch="select" cascade="save-update">
            <key>
                <column name="aid" not-null="true" />
            </key>
            <many-to-many entity-name="test.B">
                <column name="bid" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name='test.B' table='B'>
        <id name='bid' type='long' column='bid'>
        </id>
        <set name="aSet" table="AB"
            inverse="false" fetch="select" cascade="save-update">
            <key>
                <column name="bid" not-null="true" />
            </key>
            <many-to-many entity-name="test.A">
                <column name="aid" not-null="true" />
            </many-to-many>
        </set>
    </class>
</hibernate-mapping>

My table already has following data

Table A

aid | data 
---------
1   | [json data_a1]
--------------------
2   | [json data_a2]
--------------------

Table B

bid | data
-----------
1   | [json data b1]
--------------------
2   | [json data b2]

Table AB

aid | bid
----------
1   | 1
----------
1   | 2
----------
2   | 1
----------

Now When I want to update A (say with Id 1), I have only A.data populated(UI send only data related to A. It does not know anything about A-B mapping), a.bSet is null or empty. And when I save this A, it deletes entries for mapping table.

String aJson = "{aid:1, data:['newJsonData']}";
A a = JsonParser.parse(aJson);
session.saveOrUpdate(a);

Table AB becomes

aid | bid
----------
2   | 1
----------

Is there any way to avoid this delete?

Upvotes: 2

Views: 1508

Answers (1)

JB Nizet
JB Nizet

Reputation: 691625

Use merge() rather than saveOrUpdate(), and make sure you don't reset the set to a null set when merging:

String aJson = "{aid:1, data:['newJsonData']}";
A detachedA = JsonParser.parse(aJson);
A existingA = (A) session.get(A.class, detachedA.getId());
Set<B> bs = existingA.getBs(); // save the Bs to restore them afterwards
session.merge(detachedA);
existingA.setBs(bs); // restore the Bs

Upvotes: 1

Related Questions