Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -983,8 +983,6 @@ private static void bindVersionProperty(
rootClass.setDeclaredVersion( property );
}

final SimpleValue simpleValue = (SimpleValue) property.getValue();
simpleValue.setNullValue( "undefined" );
rootClass.setOptimisticLockStyle( OptimisticLockStyle.VERSION );
if ( LOG.isTraceEnabled() ) {
final SimpleValue versionValue = (SimpleValue) rootClass.getVersion().getValue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@
*/
package org.hibernate.engine.internal;

import java.lang.reflect.Constructor;
import java.util.function.Supplier;

import org.hibernate.InstantiationException;
import org.hibernate.MappingException;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.IdentifierValue;
import org.hibernate.engine.spi.SharedSessionDelegatorBaseImpl;
import org.hibernate.engine.spi.VersionValue;
import org.hibernate.mapping.KeyValue;
import org.hibernate.property.access.spi.Getter;
Expand Down Expand Up @@ -94,7 +95,8 @@ public static <T> VersionValue getUnsavedVersionValue(

// if the version of a newly instantiated object is not the same
// as the version seed value, use that as the unsaved-value
final T seedValue = jtd.seed( length, precision, scale, null );
final T seedValue = jtd.seed( length, precision, scale,
mockSession( bootVersionMapping.getBuildingContext() ) );
return jtd.areEqual( seedValue, defaultValue )
? VersionValue.UNDEFINED
: new VersionValue( defaultValue );
Expand All @@ -119,6 +121,16 @@ public static <T> VersionValue getUnsavedVersionValue(

}

private static SharedSessionDelegatorBaseImpl mockSession(MetadataBuildingContext context) {
return new SharedSessionDelegatorBaseImpl(null) {
@Override
public JdbcServices getJdbcServices() {
return context.getBootstrapContext().getServiceRegistry()
.requireService( JdbcServices.class );
}
};
}

private UnsavedValueFactory() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -405,17 +405,26 @@ protected void entityIsDetached(MergeEvent event, Object copiedId, Object origin
final Object result = source.getLoadQueryInfluencers().fromInternalFetchProfile(
CascadingFetchProfile.MERGE,
() -> source.get( entityName, clonedIdentifier )

);
if ( result == null ) {
//TODO: we should throw an exception if we really *know* for sure
// that this is a detached instance, rather than just assuming
//throw new StaleObjectStateException(entityName, id);

if ( result == null ) {
LOG.trace( "Detached instance not found in database" );
// we got here because we assumed that an instance
// with an assigned id was detached, when it was
// really persistent
entityIsTransient( event, clonedIdentifier, copyCache );
// with an assigned id and no version was detached,
// when it was really transient (or deleted)
final Boolean knownTransient = persister.isTransient( entity, source );
if ( knownTransient == Boolean.FALSE ) {
// we know for sure it's detached (generated id
// or a version property), and so the instance
// must have been deleted by another transaction
throw new StaleObjectStateException( entityName, id );
}
else {
// we know for sure it's transient, or we just
// don't have information (assigned id and no
// version property) so keep assuming transient
entityIsTransient( event, clonedIdentifier, copyCache );
}
}
else {
// before cascade!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister;

import static org.hibernate.event.internal.EventUtil.getLoggableName;

public enum EntityState {
PERSISTENT, TRANSIENT, DETACHED, DELETED;

Expand Down Expand Up @@ -44,13 +46,13 @@ public static EntityState getEntityState(
if ( entry.getStatus() != Status.DELETED ) {
// do nothing for persistent instances
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Persistent instance of: {0}", EventUtil.getLoggableName( entityName, entity ) );
LOG.tracev( "Persistent instance of: {0}", getLoggableName( entityName, entity ) );
}
return PERSISTENT;
}
// ie. e.status==DELETED
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Deleted instance of: {0}", EventUtil.getLoggableName( entityName, entity ) );
LOG.tracev( "Deleted instance of: {0}", getLoggableName( entityName, entity ) );
}
return DELETED;
}
Expand All @@ -61,12 +63,12 @@ public static EntityState getEntityState(

if ( ForeignKeys.isTransient( entityName, entity, assumedUnsaved, source ) ) {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Transient instance of: {0}", EventUtil.getLoggableName( entityName, entity ) );
LOG.tracev( "Transient instance of: {0}", getLoggableName( entityName, entity ) );
}
return TRANSIENT;
}
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Detached instance of: {0}", EventUtil.getLoggableName( entityName, entity ) );
LOG.tracev( "Detached instance of: {0}", getLoggableName( entityName, entity ) );
}

final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
import jakarta.persistence.JoinColumn;
import jakarta.persistence.OneToMany;

import jakarta.persistence.OptimisticLockException;
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
Expand All @@ -27,6 +28,7 @@
import static org.hibernate.orm.test.bytecode.enhancement.merge.MergeDetachedCascadedCollectionInEmbeddableTest.Heading;
import static org.hibernate.orm.test.bytecode.enhancement.merge.MergeDetachedCascadedCollectionInEmbeddableTest.Thing;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.fail;

import org.junit.jupiter.api.Test;

Expand Down Expand Up @@ -55,13 +57,21 @@ public void testMergeDetached(SessionFactoryScope scope) {
return entity;
} );

scope.inTransaction( session -> {
heading.name = "updated";
Heading headingMerged = (Heading) session.merge( heading );
assertNotSame( heading, headingMerged );
assertNotSame( heading.grouping, headingMerged.grouping );
assertNotSame( heading.grouping.things, headingMerged.grouping.things );
} );
try {
scope.inTransaction(session -> {
heading.name = "updated";
Heading headingMerged = session.merge(heading);
assertNotSame(heading, headingMerged);
assertNotSame(heading.grouping, headingMerged.grouping);
assertNotSame(heading.grouping.things, headingMerged.grouping.things);
fail();
});
}
catch (OptimisticLockException e) {
// expected since tx above was never committed
// so the entity had id generated but was never
// actually inserted in database
}
}

@Entity(name = "Heading")
Expand Down
Loading