2

I need to save several child objects when creating the parent object. Ideally, I want to save them in one transaction, however, I keep getting an org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session.

In this example, a SubDiscipline has many SubdisciplinePlayers.

I feel that there's something wrong with the mapping

POJOs:

Subdiscipline.java

public class Subdiscipline {

    private int id;
    private int disciplineId;
    private String name;
    private List<SubdisciplinePlayer> subdisciplinePlayers;

    public Subdiscipline() {
    }

    //standard constructors, getter & setters...
}

SubdisciplinePlayers.java

public class SubdisciplinePlayer implements Serializable {

    private int idPlayers;
    private int disciplineId;
    private int subDisciplineId;
    private int players;
    private int minPlayers;
    private int maxPlayers;

    private Subdiscipline subdiscipline;

    public SubdisciplinePlayer() {
    }
    //standard constructors, getter & setters...
}

Main.java:

public class Main {

    @SuppressWarnings("unchecked")
    public static void main(String[] args) {

        SessionFactory sf = HibernateUtil.getSessionFactory();
        Session session = sf.openSession();
        session.beginTransaction();

        Subdiscipline sd = new Subdiscipline("soccer_" + (new Date()).getTime(), new Date(), new Date(), new Status(1) );
        sd.setDisciplineId(4);
        session.save(sd);

        SubdisciplinePlayer sdp = new SubdisciplinePlayer();
        sdp.setDisciplineId(sd.getDisciplineId());
        sdp.setSubDisciplineId(sd.getId());
        sdp.setSubdiscipline(sd);
        sdp.setIdPlayers(555);

        SubdisciplinePlayer sdp2 = new SubdisciplinePlayer();
        sdp2.setDisciplineId(sd.getDisciplineId());
        sdp2.setSubDisciplineId(sd.getId());
        sdp2.setSubdiscipline(sd);
        sdp2.setIdPlayers(457);

        sd.setSubdisciplinePlayers(new ArrayList<SubdisciplinePlayer>());
        sd.getSubdisciplinePlayers().add(sdp);
        sd.getSubdisciplinePlayers().add(sdp2);

        session.save(sd);

        session.getTransaction().commit();
        session.close();

    }
}

Mappings

Subdiscipline Mapping

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="net.viralpatel.hibernate.Subdiscipline" table="sub_discipline">
        <id name="id" column="sub_dis_id" unsaved-value="0">
            <generator class="increment"/>
        </id>
        <property name="disciplineId" column="dis_id" type="int"/>
        <property name="name" column="sub_discipline" type="string"/>           
        <bag name="subdisciplinePlayers" table="sdis_players" inverse="true" cascade="all">
            <key column="sub_dis_id" />
            <one-to-many class="net.viralpatel.hibernate.SubdisciplinePlayer" />
        </bag>

    </class>
</hibernate-mapping>

SubdisciplinePlayer Mapping

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping
PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="net.viralpatel.hibernate.SubdisciplinePlayer" table="sdis_players">
        <composite-id>
            <key-property name="disciplineId" column="dis_id" type="int"/>
            <key-property name="subDisciplineId" column="sub_dis_id" type="int" />
        </composite-id>
        <property name="idPlayers" column="id_players" type="int"/>
        <property name="players" column="players" type="int"/>
        <property name="minPlayers" column="min_players" type="int"/>
        <property name="maxPlayers" column="max_players" type="int"/>
        <many-to-one name="subdiscipline" class="net.viralpatel.hibernate.Subdiscipline" cascade="none" insert="false" update="false">
            <column name="sub_dis_id"/>
        </many-to-one>
    </class>
</hibernate-mapping>

Exception thrown

Exception in thread "main" org.hibernate.NonUniqueObjectException: a different object     with the same identifier value was already associated with the session:     [net.viralpatel.hibernate.SubdisciplinePlayer#net.viralpatel.hibernate.SubdisciplinePlayer@1cd7e9c3]

2 Answers 2

3

You have declared composite key with fields disciplineId & subDisciplineId for your entity SubdisciplinePlayer.

Now in your program you are creating 2 instances of SubdisciplinePlayer with same composite id.

SubdisciplinePlayer sdp = new SubdisciplinePlayer();
sdp.setDisciplineId(sd.getDisciplineId());
sdp.setSubDisciplineId(sd.getId());

SubdisciplinePlayer sdp2 = new SubdisciplinePlayer();
sdp2.setDisciplineId(sd.getDisciplineId());
sdp2.setSubDisciplineId(sd.getId());

So when you call Session.save(sd), hibernate observed that you are trying to save 2 instances of SubdisciplinePlayer and throwing the exception as :

org.hibernate.NonUniqueObjectException: a different objectwith the same identifier 
value was already associated with the session:     
[net.viralpatel.hibernate.SubdisciplinePlayer#
net.viralpatel.hibernate.SubdisciplinePlayer@1cd7e9c3]

To fix the issue just make sure that the composite id of SubdisciplinePlayer should have different values as primary key should be unique.

Sign up to request clarification or add additional context in comments.

1 Comment

Now that you point this out, seems obvious, thanks. The problem is that the field idPlayers is an autoincrement field, part of the composite key of SubDisciplinePlayers. How can I modify the mapping to reflect this?
1

Please use merge instead of save when you are trying with second time save.

   sd.setSubdisciplinePlayers(new ArrayList<SubdisciplinePlayer>());
   sd.getSubdisciplinePlayers().add(sdp);
   sd.getSubdisciplinePlayers().add(sdp2);
   session.merge(sd);

I listed out more ref for you.

Ref 1

Ref 2

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.