简体   繁体   中英

org.hibernate.NonUniqueObjectException when saving a list of child objects

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]

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.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM