-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Session.merge() fails, Session.saveOrUpdate() works
PostPosted: Fri Nov 02, 2007 12:50 am 
Newbie

Joined: Wed Oct 04, 2006 2:47 am
Posts: 12
Can anyone explain why the following use of Session.merge() fails with a ConstraintViolationException,
but replacing merge() with saveOrUpdate() succeeds?

Using merge(), hibernate attempts to insert the Relationship instance associated with partA and partB twice.

Thanks,

Tim

Hibernate version:

3.2.5

Mapping documents:

Code:
<?xml version="1.0"?>

<!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.Component" table="components">
        <id name="id" type="long" unsaved-value="-1">
          <generator class="native" />
        </id>
        <version name="version" access="property" type="long" />
        <property name="UUID" type="string" length="36" unique="true"/>
        <set name="sourceRelationships" access="property" inverse="true"
             cascade="all-delete-orphan" lazy="false">
          <key column="source" property-ref="UUID" not-null="true"/>
          <one-to-many class="test.Relationship" />
        </set>
        <set name="targetRelationships" access="property" inverse="true"
             cascade="all-delete-orphan" lazy="false">
          <key column="target" property-ref="UUID" not-null="true"/>
          <one-to-many class="test.Relationship" />
        </set>
    </class>

    <class name="test.Relationship" table="relationships">
        <id name="id" type="long" unsaved-value="-1">
          <generator class="native" />
        </id>
        <version name="version" access="property" type="long" />
        <property name="UUID" type="string" length="36" unique="true"/>
        <property name="source" type="string"/>
        <property name="target" type="string"/>
    </class>

</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

Code:
        Component partA = new Component();
        Component partB = new Component();

        Relationship r1 = partA.addRelationship(partB, true);
        Transaction tx = session.beginTransaction();
        session.merge(partA);
        session.merge(partB);
        tx.commit();


Full stack trace of any exception that occurs:

org.hibernate.exception.ConstraintViolationException: could not insert: [test.Relationship]
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:71)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:40)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2158)
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:2638)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:48)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:186)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:123)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:687)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:669)
at org.hibernate.engine.CascadingAction$6.cascade(CascadingAction.java:245)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:268)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:216)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:296)
at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:242)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:219)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:169)
at org.hibernate.engine.Cascade.cascade(Cascade.java:130)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:456)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:194)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:123)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
at test.TestCase.testMerge(TestCase.java:136)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit2.JUnitStarter.main(JUnitStarter.java:32)
Caused by: com.mysql.jdbc.exceptions.MySQLIntegrityConstraintViolationException: Duplicate entry '23f15f39-a0c1-44bf-82ec-edb0f13982c5' for key 2
at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:931)
at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:2822)
at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1536)
at com.mysql.jdbc.ServerPreparedStatement.serverExecute(ServerPreparedStatement.java:1159)
at com.mysql.jdbc.ServerPreparedStatement.executeInternal(ServerPreparedStatement.java:684)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1184)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1101)
at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:1086)
at org.apache.commons.dbcp.DelegatingPreparedStatement.executeUpdate(DelegatingPreparedStatement.java:101)
at org.hibernate.id.IdentityGenerator$GetGeneratedKeysDelegate.executeAndExtract(IdentityGenerator.java:73)
at org.hibernate.id.insert.AbstractReturningDelegate.performInsert(AbstractReturningDelegate.java:33)
... 46 more


Classes

Code:

public class Component extends IMObject {

    private Set<Relationship> sourceRelationships = new HashSet<Relationship>();
    private Set<Relationship> targetRelationships = new HashSet<Relationship>();

    public Component() {
    }

    public Set<Relationship> getSourceRelationships() {
        return sourceRelationships;
    }

    public void setSourceRelationships(Set<Relationship> sourceRelationships) {
        this.sourceRelationships = sourceRelationships;
    }

    public Set<Relationship> getTargetRelationships() {
        return targetRelationships;
    }

    public void setTargetRelationships(Set<Relationship> targetRelationships) {
        this.targetRelationships = targetRelationships;
    }

    public Relationship addRelationship(Component component, boolean target) {
        Relationship r = new Relationship();
        if (target) {
            r.setSource(getUUID());
            r.setTarget(component.getUUID());
            sourceRelationships.add(r);
            component.targetRelationships.add(r);
        } else {
            r.setSource(component.getUUID());
            r.setTarget(getUUID());
            targetRelationships.add(r);
            component.sourceRelationships.add(r);
        }
        return r;
    }
}

public class IMObject {
    private long id = -1;
    private String uuid;
    private long version;

    public long getId() {
        return id;
    }

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

    public String getUUID() {
        if (uuid == null) {
           uuid = UUID.randomUUID().toString();
        }
        return uuid;
    }

    public void setUUID(String uuid) {
        this.uuid = uuid;
    }

    public boolean equals(Object object) {
        if (object instanceof IMObject) {
            return ((IMObject) object).getUUID().equals(getUUID());
        }
        return false;
    }

    public int hashCode() {
        return getUUID().hashCode();
    }

    public long getVersion() {
        return version;
    }

    public void setVersion(long version) {
        this.version = version;
    }
}

public class Relationship extends IMObject {

    private String source;
    private String target;

    public Relationship() {
    }

    public Relationship(Component source, Component target) {
        this.source = source.getUUID();
        this.target = target.getUUID();
    }

    public String getSource() {
        return source;
    }

    public void setSource(String source) {
        this.source = source;
    }

    public String getTarget() {
        return target;
    }

    public void setTarget(String target) {
        this.target = target;
    }

}



Name and version of the database you are using:

MySQL 5.0.24a

The generated SQL (show_sql=true):

insert into components (version, UUID) values (?, ?)
insert into relationships (version, UUID, source, target) values (?, ?, ?, ?)
insert into components (version, UUID) values (?, ?)
insert into relationships (version, UUID, source, target) values (?, ?, ?, ?)

Debug level Hibernate log excerpt:

15:24:13,375 DEBUG JDBCContext,main:210 - after transaction begin
15:24:22,359 DEBUG VersionValue,main:44 - version unsaved-value strategy UNDEFINED
15:24:22,375 DEBUG IdentifierValue,main:104 - id unsaved-value: -1
15:24:22,375 DEBUG AbstractSaveEventListener,main:514 - transient instance of: test.Component
15:24:22,375 DEBUG DefaultMergeEventListener,main:160 - merging transient instance
15:24:22,390 DEBUG Cascade,main:115 - processing cascade ACTION_MERGE for: test.Component
15:24:22,390 DEBUG Cascade,main:150 - done processing cascade ACTION_MERGE for: test.Component
15:24:22,421 DEBUG AbstractSaveEventListener,main:153 - saving [test.Component#<null>]
15:24:22,421 DEBUG AbstractSaveEventListener,main:244 - executing insertions
15:24:22,437 DEBUG Versioning,main:91 - using initial version: 0
15:24:22,468 DEBUG WrapVisitor,main:87 - Wrapped collection in role: test.Component.sourceRelationships
15:24:22,468 DEBUG WrapVisitor,main:87 - Wrapped collection in role: test.Component.targetRelationships
15:24:22,500 DEBUG AbstractSaveEventListener,main:297 - executing identity-insert immediately
15:24:22,500 DEBUG UpdateTimestampsCache,main:50 - Pre-invalidating space [components]
15:24:22,515 DEBUG AbstractEntityPersister,main:2144 - Inserting entity: test.Component (native id)
15:24:22,515 DEBUG AbstractEntityPersister,main:2146 - Version: 0
15:24:22,531 DEBUG AbstractBatcher,main:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
15:24:22,531 DEBUG SQL,main:401 - insert into components (version, UUID) values (?, ?)
15:24:22,531 DEBUG AbstractBatcher,main:484 - preparing statement
15:24:22,578 DEBUG AbstractEntityPersister,main:1992 - Dehydrating entity: [test.Component#<null>]
15:24:22,593 DEBUG LongType,main:133 - binding '0' to parameter: 1
15:24:22,593 DEBUG StringType,main:133 - binding 'b520b6ea-3937-4d0e-9ca8-07fcbdf09218' to parameter: 2
15:24:22,609 DEBUG IdentifierGeneratorFactory,main:37 - Natively generated identity: 14
15:24:22,609 DEBUG AbstractBatcher,main:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
15:24:22,609 DEBUG AbstractBatcher,main:533 - closing statement
15:24:22,625 DEBUG Cascade,main:115 - processing cascade ACTION_MERGE for: test.Component
15:24:22,640 DEBUG Cascade,main:291 - cascade ACTION_MERGE for collection: test.Component.sourceRelationships
15:24:22,640 DEBUG CascadingAction,main:243 - cascading to merge: test.Relationship
15:24:22,640 DEBUG VersionValue,main:44 - version unsaved-value strategy UNDEFINED
15:24:22,656 DEBUG IdentifierValue,main:104 - id unsaved-value: -1
15:24:22,656 DEBUG AbstractSaveEventListener,main:514 - transient instance of: test.Relationship
15:24:22,671 DEBUG DefaultMergeEventListener,main:160 - merging transient instance
15:24:22,671 DEBUG AbstractSaveEventListener,main:153 - saving [test.Relationship#<null>]
15:24:22,671 DEBUG AbstractSaveEventListener,main:244 - executing insertions
15:24:22,687 DEBUG Versioning,main:91 - using initial version: 0
15:24:22,687 DEBUG AbstractSaveEventListener,main:297 - executing identity-insert immediately
15:24:22,703 DEBUG UpdateTimestampsCache,main:50 - Pre-invalidating space [relationships]
15:24:22,703 DEBUG AbstractEntityPersister,main:2144 - Inserting entity: test.Relationship (native id)
15:24:22,718 DEBUG AbstractEntityPersister,main:2146 - Version: 0
15:24:22,718 DEBUG AbstractBatcher,main:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
15:24:22,718 DEBUG SQL,main:401 - insert into relationships (version, UUID, source, target) values (?, ?, ?, ?)
15:24:22,734 DEBUG AbstractBatcher,main:484 - preparing statement
15:24:22,734 DEBUG AbstractEntityPersister,main:1992 - Dehydrating entity: [test.Relationship#<null>]
15:24:22,750 DEBUG LongType,main:133 - binding '0' to parameter: 1
15:24:22,750 DEBUG StringType,main:133 - binding 'a4eed1ae-9acd-4043-86e3-1135e42410f9' to parameter: 2
15:24:22,765 DEBUG StringType,main:133 - binding 'b520b6ea-3937-4d0e-9ca8-07fcbdf09218' to parameter: 3
15:24:22,765 DEBUG StringType,main:133 - binding 'd422bc5d-f7c3-4dec-906d-038655e2fccd' to parameter: 4
15:24:22,781 DEBUG IdentifierGeneratorFactory,main:37 - Natively generated identity: 8
15:24:22,781 DEBUG AbstractBatcher,main:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
15:24:22,796 DEBUG AbstractBatcher,main:533 - closing statement
15:24:22,796 DEBUG Cascade,main:306 - done cascade ACTION_MERGE for collection: test.Component.sourceRelationships
15:24:22,796 DEBUG Cascade,main:291 - cascade ACTION_MERGE for collection: test.Component.targetRelationships
15:24:22,812 DEBUG Cascade,main:306 - done cascade ACTION_MERGE for collection: test.Component.targetRelationships
15:24:22,812 DEBUG Cascade,main:150 - done processing cascade ACTION_MERGE for: test.Component
15:24:23,718 DEBUG VersionValue,main:44 - version unsaved-value strategy UNDEFINED
15:24:23,734 DEBUG IdentifierValue,main:104 - id unsaved-value: -1
15:24:23,734 DEBUG AbstractSaveEventListener,main:514 - transient instance of: test.Component
15:24:23,734 DEBUG DefaultMergeEventListener,main:160 - merging transient instance
15:24:23,750 DEBUG Cascade,main:115 - processing cascade ACTION_MERGE for: test.Component
15:24:23,750 DEBUG Cascade,main:150 - done processing cascade ACTION_MERGE for: test.Component
15:24:23,750 DEBUG AbstractSaveEventListener,main:153 - saving [test.Component#<null>]
15:24:23,765 DEBUG AbstractSaveEventListener,main:244 - executing insertions
15:24:23,781 DEBUG Versioning,main:91 - using initial version: 0
15:24:23,781 DEBUG WrapVisitor,main:87 - Wrapped collection in role: test.Component.sourceRelationships
15:24:23,781 DEBUG WrapVisitor,main:87 - Wrapped collection in role: test.Component.targetRelationships
15:24:23,796 DEBUG AbstractSaveEventListener,main:297 - executing identity-insert immediately
15:24:23,796 DEBUG UpdateTimestampsCache,main:50 - Pre-invalidating space [components]
15:24:23,796 DEBUG AbstractEntityPersister,main:2144 - Inserting entity: test.Component (native id)
15:24:23,812 DEBUG AbstractEntityPersister,main:2146 - Version: 0
15:24:23,812 DEBUG AbstractBatcher,main:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
15:24:23,812 DEBUG SQL,main:401 - insert into components (version, UUID) values (?, ?)
15:24:23,828 DEBUG AbstractBatcher,main:484 - preparing statement
15:24:23,828 DEBUG AbstractEntityPersister,main:1992 - Dehydrating entity: [test.Component#<null>]
15:24:23,843 DEBUG LongType,main:133 - binding '0' to parameter: 1
15:24:23,843 DEBUG StringType,main:133 - binding 'd422bc5d-f7c3-4dec-906d-038655e2fccd' to parameter: 2
15:24:23,859 DEBUG IdentifierGeneratorFactory,main:37 - Natively generated identity: 15
15:24:23,859 DEBUG AbstractBatcher,main:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
15:24:23,859 DEBUG AbstractBatcher,main:533 - closing statement
15:24:23,875 DEBUG Cascade,main:115 - processing cascade ACTION_MERGE for: test.Component
15:24:23,875 DEBUG Cascade,main:291 - cascade ACTION_MERGE for collection: test.Component.sourceRelationships
15:24:23,890 DEBUG Cascade,main:306 - done cascade ACTION_MERGE for collection: test.Component.sourceRelationships
15:24:23,890 DEBUG Cascade,main:291 - cascade ACTION_MERGE for collection: test.Component.targetRelationships
15:24:23,890 DEBUG CascadingAction,main:243 - cascading to merge: test.Relationship
15:24:23,906 DEBUG VersionValue,main:44 - version unsaved-value strategy UNDEFINED
15:24:23,906 DEBUG IdentifierValue,main:104 - id unsaved-value: -1
15:24:23,906 DEBUG AbstractSaveEventListener,main:514 - transient instance of: test.Relationship
15:24:23,921 DEBUG DefaultMergeEventListener,main:160 - merging transient instance
15:24:23,921 DEBUG AbstractSaveEventListener,main:153 - saving [test.Relationship#<null>]
15:24:23,921 DEBUG AbstractSaveEventListener,main:244 - executing insertions
15:24:23,937 DEBUG Versioning,main:91 - using initial version: 0
15:24:23,953 DEBUG AbstractSaveEventListener,main:297 - executing identity-insert immediately
15:24:23,953 DEBUG UpdateTimestampsCache,main:50 - Pre-invalidating space [relationships]
15:24:23,968 DEBUG AbstractEntityPersister,main:2144 - Inserting entity: test.Relationship (native id)
15:24:23,968 DEBUG AbstractEntityPersister,main:2146 - Version: 0
15:24:23,984 DEBUG AbstractBatcher,main:366 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
15:24:23,984 DEBUG SQL,main:401 - insert into relationships (version, UUID, source, target) values (?, ?, ?, ?)
15:24:24,000 DEBUG AbstractBatcher,main:484 - preparing statement
15:24:24,000 DEBUG AbstractEntityPersister,main:1992 - Dehydrating entity: [test.Relationship#<null>]
15:24:24,015 DEBUG LongType,main:133 - binding '0' to parameter: 1
15:24:24,015 DEBUG StringType,main:133 - binding 'a4eed1ae-9acd-4043-86e3-1135e42410f9' to parameter: 2
15:24:24,031 DEBUG StringType,main:133 - binding 'b520b6ea-3937-4d0e-9ca8-07fcbdf09218' to parameter: 3
15:24:24,031 DEBUG StringType,main:133 - binding 'd422bc5d-f7c3-4dec-906d-038655e2fccd' to parameter: 4
15:24:24,109 DEBUG AbstractBatcher,main:374 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
15:24:24,109 DEBUG AbstractBatcher,main:533 - closing statement
15:24:24,140 DEBUG JDBCExceptionReporter,main:69 - could not insert: [test.Relationship] [insert into relationships (version, UUID, source, target) values (?, ?, ?, ?)]


Top
 Profile  
 
 Post subject: [WORKAROUND] Session.merge() fails, saveOrUpdate() works
PostPosted: Mon Nov 05, 2007 1:45 am 
Newbie

Joined: Wed Oct 04, 2006 2:47 am
Posts: 12
The problem seems to be that as Relationship is a transient instance that
doesn't get associated with the session after the first call to merge(),
hibernate treats it as a transient instance on the second call as well.

A workaround to this is to either:

1. save the Relationship first. ie.
Code:
        Relationship r1 = partA.addRelationship(partB, true);
        Transaction tx = session.beginTransaction();
        session.saveOrUpdate(r1);
        session.merge(partA);
        session.merge(partB);
        tx.commit();


2. register Spring's IdTransferringMergeEventListener with the SessionFactory

This is a hack. The merge listener updates the id of the Relationship when
Session.merge() is invoked, so hibernate treats it as a detached instance on
the second call.


Top
 Profile  
 
 Post subject: Session.merge() fails, Session.saveOrUpdate() works
PostPosted: Sun Nov 18, 2007 10:57 am 
Newbie

Joined: Sun Nov 18, 2007 10:43 am
Posts: 1
Hello,
Which one is the preferred solution?
Can I use the second solution (IdTransferringMergeEventListener) even if I am using just Hibernate (3.2) and not Spring ?

Regards,
Kedar Dravid


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.