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
ClassesCode:
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 (?, ?, ?, ?)]