HHH-17971 - Remove ALLOW_REFRESH_DETACHED_ENTITY
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
parent
2be3000e40
commit
3818b6d99f
|
@ -886,16 +886,7 @@ See the discussion of non-identifier <<chapters/domain/basic_types.adoc#mapping-
|
||||||
[IMPORTANT]
|
[IMPORTANT]
|
||||||
====
|
====
|
||||||
Traditionally, Hibernate allowed detached entities to be refreshed.
|
Traditionally, Hibernate allowed detached entities to be refreshed.
|
||||||
Unfortunately, Jakarta Persistence prohibits this practice and specifies that an `IllegalArgumentException` should be thrown instead.
|
however, Jakarta Persistence prohibits this practice and specifies that an `IllegalArgumentException` should be thrown instead. This is the default behaviour from version 7.0 onwards.
|
||||||
|
|
||||||
For this reason, when bootstrapping the Hibernate `SessionFactory` using the native API, the legacy detached entity refresh behavior is going to be preserved.
|
|
||||||
On the other hand, when bootstrapping Hibernate through the Jakarta Persistence `EntityManagerFactory` building process, detached entities are not allowed to be refreshed by default.
|
|
||||||
|
|
||||||
However, this default behavior can be overwritten through the `hibernate.allow_refresh_detached_entity` configuration property.
|
|
||||||
If this property is explicitly set to `true`, then you can refresh detached entities even when using the Jakarta Persistence bootstraps mechanism, therefore bypassing the Jakarta Persistence specification restriction.
|
|
||||||
|
|
||||||
For more about the `hibernate.allow_refresh_detached_entity` configuration property,
|
|
||||||
check out the <<appendices/Configurations.adoc#misc,Configurations>> section as well.
|
|
||||||
====
|
====
|
||||||
|
|
||||||
[[pc-refresh-gotchas]]
|
[[pc-refresh-gotchas]]
|
||||||
|
|
|
@ -426,11 +426,6 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void disableRefreshDetachedEntity() {
|
|
||||||
this.optionsBuilder.disableRefreshDetachedEntity();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void disableJtaTransactionAccess() {
|
public void disableJtaTransactionAccess() {
|
||||||
this.optionsBuilder.disableJtaTransactionAccess();
|
this.optionsBuilder.disableJtaTransactionAccess();
|
||||||
|
|
|
@ -75,7 +75,6 @@ import org.hibernate.type.format.jaxb.JaxbXmlFormatMapper;
|
||||||
import jakarta.persistence.criteria.Nulls;
|
import jakarta.persistence.criteria.Nulls;
|
||||||
|
|
||||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS;
|
import static org.hibernate.cfg.AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS;
|
||||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY;
|
|
||||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_UPDATE_OUTSIDE_TRANSACTION;
|
import static org.hibernate.cfg.AvailableSettings.ALLOW_UPDATE_OUTSIDE_TRANSACTION;
|
||||||
import static org.hibernate.cfg.AvailableSettings.AUTO_CLOSE_SESSION;
|
import static org.hibernate.cfg.AvailableSettings.AUTO_CLOSE_SESSION;
|
||||||
import static org.hibernate.cfg.AvailableSettings.AUTO_EVICT_COLLECTION_CACHE;
|
import static org.hibernate.cfg.AvailableSettings.AUTO_EVICT_COLLECTION_CACHE;
|
||||||
|
@ -176,7 +175,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
||||||
private boolean jtaTransactionAccessEnabled;
|
private boolean jtaTransactionAccessEnabled;
|
||||||
private boolean allowOutOfTransactionUpdateOperations;
|
private boolean allowOutOfTransactionUpdateOperations;
|
||||||
private boolean releaseResourcesOnCloseEnabled;
|
private boolean releaseResourcesOnCloseEnabled;
|
||||||
private boolean allowRefreshDetachedEntity;
|
|
||||||
|
|
||||||
// (JTA) transaction handling
|
// (JTA) transaction handling
|
||||||
private boolean jtaTrackByThread;
|
private boolean jtaTrackByThread;
|
||||||
|
@ -335,12 +333,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
||||||
true
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
this.allowRefreshDetachedEntity = configurationService.getSetting(
|
|
||||||
ALLOW_REFRESH_DETACHED_ENTITY,
|
|
||||||
BOOLEAN,
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
this.flushBeforeCompletionEnabled = configurationService.getSetting( FLUSH_BEFORE_COMPLETION, BOOLEAN, true );
|
this.flushBeforeCompletionEnabled = configurationService.getSetting( FLUSH_BEFORE_COMPLETION, BOOLEAN, true );
|
||||||
this.autoCloseSessionEnabled = configurationService.getSetting( AUTO_CLOSE_SESSION, BOOLEAN, false );
|
this.autoCloseSessionEnabled = configurationService.getSetting( AUTO_CLOSE_SESSION, BOOLEAN, false );
|
||||||
|
|
||||||
|
@ -906,11 +898,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
||||||
return jtaTransactionAccessEnabled;
|
return jtaTransactionAccessEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isAllowRefreshDetachedEntity() {
|
|
||||||
return allowRefreshDetachedEntity;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAllowOutOfTransactionUpdateOperations() {
|
public boolean isAllowOutOfTransactionUpdateOperations() {
|
||||||
return allowOutOfTransactionUpdateOperations;
|
return allowOutOfTransactionUpdateOperations;
|
||||||
|
@ -1624,10 +1611,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
||||||
this.collectionsInDefaultFetchGroupEnabled = enabled;
|
this.collectionsInDefaultFetchGroupEnabled = enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void disableRefreshDetachedEntity() {
|
|
||||||
this.allowRefreshDetachedEntity = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disableJtaTransactionAccess() {
|
public void disableJtaTransactionAccess() {
|
||||||
this.jtaTransactionAccessEnabled = false;
|
this.jtaTransactionAccessEnabled = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,8 @@ import org.hibernate.type.format.FormatMapper;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.Nulls;
|
import jakarta.persistence.criteria.Nulls;
|
||||||
|
|
||||||
|
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convenience base class for custom implementations of {@link SessionFactoryOptions}
|
* Convenience base class for custom implementations of {@link SessionFactoryOptions}
|
||||||
* using delegation.
|
* using delegation.
|
||||||
|
@ -77,8 +79,13 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
||||||
return delegate.isJtaTransactionAccessEnabled();
|
return delegate.isJtaTransactionAccessEnabled();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated with no replacement.
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "7.0", forRemoval = true)
|
||||||
@Override
|
@Override
|
||||||
public boolean isAllowRefreshDetachedEntity() {
|
public boolean isAllowRefreshDetachedEntity() {
|
||||||
|
DEPRECATION_LOGGER.deprecatedRefreshLockDetachedEntity();
|
||||||
return delegate.isAllowRefreshDetachedEntity();
|
return delegate.isAllowRefreshDetachedEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package org.hibernate.boot.spi;
|
package org.hibernate.boot.spi;
|
||||||
|
|
||||||
import org.hibernate.boot.SessionFactoryBuilder;
|
import org.hibernate.boot.SessionFactoryBuilder;
|
||||||
|
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Additional SPI contract for {@link SessionFactoryBuilder}, mainly intended for
|
* Additional SPI contract for {@link SessionFactoryBuilder}, mainly intended for
|
||||||
|
@ -21,10 +22,11 @@ public interface SessionFactoryBuilderImplementor extends SessionFactoryBuilder
|
||||||
void disableJtaTransactionAccess();
|
void disableJtaTransactionAccess();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called if {@link org.hibernate.cfg.AvailableSettings#ALLOW_REFRESH_DETACHED_ENTITY}
|
* @deprecated with no replacement.
|
||||||
* is not enabled.
|
|
||||||
*/
|
*/
|
||||||
|
@Deprecated(since = "7.0", forRemoval = true)
|
||||||
default void disableRefreshDetachedEntity() {
|
default void disableRefreshDetachedEntity() {
|
||||||
|
DEPRECATION_LOGGER.deprecatedRefreshLockDetachedEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -34,6 +34,8 @@ import org.hibernate.type.format.FormatMapper;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.Nulls;
|
import jakarta.persistence.criteria.Nulls;
|
||||||
|
|
||||||
|
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregator of special options used to build the {@link org.hibernate.SessionFactory}.
|
* Aggregator of special options used to build the {@link org.hibernate.SessionFactory}.
|
||||||
*
|
*
|
||||||
|
@ -76,7 +78,12 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
|
||||||
|
|
||||||
boolean isJtaTransactionAccessEnabled();
|
boolean isJtaTransactionAccessEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated with no replacement.
|
||||||
|
*/
|
||||||
|
@Deprecated(since = "7.0", forRemoval = true)
|
||||||
default boolean isAllowRefreshDetachedEntity() {
|
default boolean isAllowRefreshDetachedEntity() {
|
||||||
|
DEPRECATION_LOGGER.deprecatedRefreshLockDetachedEntity();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -120,24 +120,6 @@ public interface AvailableSettings
|
||||||
*/
|
*/
|
||||||
String DELAY_ENTITY_LOADER_CREATIONS = "hibernate.loader.delay_entity_loader_creations";
|
String DELAY_ENTITY_LOADER_CREATIONS = "hibernate.loader.delay_entity_loader_creations";
|
||||||
|
|
||||||
/**
|
|
||||||
* When enabled, allows calls to {@link jakarta.persistence.EntityManager#refresh(Object)}
|
|
||||||
* and {@link org.hibernate.Session#refresh(Object)} on a detached entity instance.
|
|
||||||
* <p>
|
|
||||||
* Values are {@code true}, which allows refreshing a detached instance and {@code false},
|
|
||||||
* which does not. When refreshing is disallowed, an {@link IllegalArgumentException}
|
|
||||||
* is thrown.
|
|
||||||
* <p>
|
|
||||||
* The default behavior is to allow refreshing a detached instance unless Hibernate
|
|
||||||
* is bootstrapped via JPA.
|
|
||||||
*
|
|
||||||
* @deprecated Will be removed with no replacement from ORM version 7 onwards
|
|
||||||
*
|
|
||||||
* @since 5.2
|
|
||||||
*/
|
|
||||||
@Deprecated(since="6.6", forRemoval = true)
|
|
||||||
String ALLOW_REFRESH_DETACHED_ENTITY = "hibernate.allow_refresh_detached_entity";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specifies how Hibernate should behave when multiple representations of the same
|
* Specifies how Hibernate should behave when multiple representations of the same
|
||||||
* persistent entity instance, that is, multiple detached objects with the same
|
* persistent entity instance, that is, multiple detached objects with the same
|
||||||
|
|
|
@ -1245,10 +1245,8 @@ public class SessionImpl
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkEntityManaged(String entityName, Object entity) {
|
private void checkEntityManaged(String entityName, Object entity) {
|
||||||
if ( !getSessionFactory().getSessionFactoryOptions().isAllowRefreshDetachedEntity() ) {
|
if ( !managed( entityName, entity ) ) {
|
||||||
if ( !managed( entityName, entity ) ) {
|
throw new IllegalArgumentException( "Given entity is not associated with the persistence context" );
|
||||||
throw new IllegalArgumentException( "Given entity is not associated with the persistence context" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,4 +187,11 @@ public interface DeprecationLogger extends BasicLogger {
|
||||||
value = "Encountered use of deprecated annotation [%s] at %s."
|
value = "Encountered use of deprecated annotation [%s] at %s."
|
||||||
)
|
)
|
||||||
void deprecatedAnnotation(Class<? extends Annotation> annotationType, String locationDescription);
|
void deprecatedAnnotation(Class<? extends Annotation> annotationType, String locationDescription);
|
||||||
|
|
||||||
|
@LogMessage(level = WARN)
|
||||||
|
@Message(
|
||||||
|
id = 90000034,
|
||||||
|
value = "Refreshing/locking detached entities is no longer allowed."
|
||||||
|
)
|
||||||
|
void deprecatedRefreshLockDetachedEntity();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1479,7 +1479,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
|
||||||
// builder.applyInterceptor( sessionFactoryInterceptor );
|
// builder.applyInterceptor( sessionFactoryInterceptor );
|
||||||
// }
|
// }
|
||||||
handleAllowJtaTransactionAccess( builder );
|
handleAllowJtaTransactionAccess( builder );
|
||||||
handleAllowDetachedEntity( builder );
|
|
||||||
addConfiguredSessionFactoryObserver( builder );
|
addConfiguredSessionFactoryObserver( builder );
|
||||||
builder.addSessionFactoryObservers( ServiceRegistryCloser.INSTANCE );
|
builder.addSessionFactoryObservers( ServiceRegistryCloser.INSTANCE );
|
||||||
builder.applyEntityNotFoundDelegate( JpaEntityNotFoundDelegate.INSTANCE );
|
builder.applyEntityNotFoundDelegate( JpaEntityNotFoundDelegate.INSTANCE );
|
||||||
|
@ -1500,16 +1499,6 @@ public class EntityManagerFactoryBuilderImpl implements EntityManagerFactoryBuil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// will use user override value or default to false if not supplied to follow JPA spec
|
|
||||||
private void handleAllowDetachedEntity(SessionFactoryBuilder builder) {
|
|
||||||
final boolean allowRefreshDetachedEntity =
|
|
||||||
readBooleanConfigurationValue( AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY );
|
|
||||||
if ( !allowRefreshDetachedEntity
|
|
||||||
&& builder instanceof SessionFactoryBuilderImplementor implementor ) {
|
|
||||||
implementor.disableRefreshDetachedEntity();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// will use user override value or default to false if not supplied to follow JPA spec
|
// will use user override value or default to false if not supplied to follow JPA spec
|
||||||
private void handleAllowJtaTransactionAccess(SessionFactoryBuilder builder) {
|
private void handleAllowJtaTransactionAccess(SessionFactoryBuilder builder) {
|
||||||
final boolean jtaTransactionAccessEnabled =
|
final boolean jtaTransactionAccessEnabled =
|
||||||
|
|
|
@ -5,15 +5,13 @@
|
||||||
package org.hibernate.orm.test.bytecode.enhancement.lazy.HHH_10708;
|
package org.hibernate.orm.test.bytecode.enhancement.lazy.HHH_10708;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -34,7 +32,6 @@ import java.util.Set;
|
||||||
)
|
)
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@BytecodeEnhanced
|
@BytecodeEnhanced
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class UnexpectedDeleteTest2 {
|
public class UnexpectedDeleteTest2 {
|
||||||
|
|
||||||
private Bar myBar;
|
private Bar myBar;
|
||||||
|
@ -59,8 +56,10 @@ public class UnexpectedDeleteTest2 {
|
||||||
@Test
|
@Test
|
||||||
public void test(SessionFactoryScope scope) {
|
public void test(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( s -> {
|
scope.inTransaction( s -> {
|
||||||
s.refresh( myBar );
|
assertThrows(IllegalArgumentException.class,
|
||||||
assertFalse( myBar.foos.isEmpty() );
|
() -> s.refresh( myBar ),
|
||||||
|
"Given entity is not associated with the persistence context"
|
||||||
|
);
|
||||||
|
|
||||||
// The issue is that currently, for some unknown reason, foos are deleted on flush
|
// The issue is that currently, for some unknown reason, foos are deleted on flush
|
||||||
} );
|
} );
|
||||||
|
|
|
@ -6,7 +6,6 @@ package org.hibernate.orm.test.bytecode.enhancement.lazy.backref;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext;
|
import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext;
|
||||||
import org.hibernate.orm.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking.DirtyCheckEnhancementContext;
|
import org.hibernate.orm.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking.DirtyCheckEnhancementContext;
|
||||||
|
@ -17,14 +16,13 @@ import org.hibernate.orm.test.collection.backref.map.compkey.Product;
|
||||||
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext;
|
||||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
@ -42,7 +40,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@BytecodeEnhanced
|
@BytecodeEnhanced
|
||||||
@CustomEnhancementContext({ NoDirtyCheckingContext.class, DirtyCheckEnhancementContext.class })
|
@CustomEnhancementContext({ NoDirtyCheckingContext.class, DirtyCheckEnhancementContext.class })
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class BackrefCompositeMapKeyTest {
|
public class BackrefCompositeMapKeyTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -123,7 +120,7 @@ public class BackrefCompositeMapKeyTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||||
Product prod = new Product( "Widget" );
|
Product prod = new Product( "Widget" );
|
||||||
MapKey mapKey = new MapKey( "Top" );
|
MapKey mapKey = new MapKey( "Top" );
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
|
@ -139,14 +136,16 @@ public class BackrefCompositeMapKeyTest {
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.lock( prod, LockMode.READ );
|
assertThrows(IllegalArgumentException.class,
|
||||||
prod.getParts().remove( mapKey );
|
() -> session.lock( prod, LockMode.READ ),
|
||||||
|
"Given entity is not associated with the persistence context"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
assertNull( session.get( Part.class, "Widge" ) );
|
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||||
assertNotNull( session.get( Part.class, "Get" ) );
|
assertNotNull( session.get( Part.class, "Get" ) );
|
||||||
session.remove( session.get( Product.class, "Widget" ) );
|
session.remove( session.get( Product.class, "Widget" ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,6 @@ package org.hibernate.orm.test.bytecode.enhancement.orphan;
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.internal.util.SerializationHelper;
|
import org.hibernate.internal.util.SerializationHelper;
|
||||||
import org.hibernate.orm.test.orphan.Part;
|
import org.hibernate.orm.test.orphan.Part;
|
||||||
import org.hibernate.orm.test.orphan.Product;
|
import org.hibernate.orm.test.orphan.Product;
|
||||||
|
@ -17,15 +16,14 @@ import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext;
|
||||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,7 +40,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
EnhancerTestContext.class, // supports laziness and dirty-checking
|
EnhancerTestContext.class, // supports laziness and dirty-checking
|
||||||
DefaultEnhancementContext.class
|
DefaultEnhancementContext.class
|
||||||
})
|
})
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class OrphanTest {
|
public class OrphanTest {
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -152,7 +149,7 @@ public class OrphanTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||||
Product prod = new Product();
|
Product prod = new Product();
|
||||||
Part part = new Part();
|
Part part = new Part();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
|
@ -172,14 +169,16 @@ public class OrphanTest {
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.lock( prod, LockMode.READ );
|
assertThrows(IllegalArgumentException.class,
|
||||||
prod.getParts().remove( part );
|
() -> session.lock( prod, LockMode.READ ),
|
||||||
|
"Given entity is not associated with the persistence context"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
assertNull( session.get( Part.class, "Widge" ) );
|
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||||
assertNotNull( session.get( Part.class, "Get" ) );
|
assertNotNull( session.get( Part.class, "Get" ) );
|
||||||
session.remove( session.get( Product.class, "Widget" ) );
|
session.remove( session.get( Product.class, "Widget" ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,18 +19,17 @@ import jakarta.persistence.OneToMany;
|
||||||
import jakarta.persistence.Table;
|
import jakarta.persistence.Table;
|
||||||
import jakarta.persistence.Temporal;
|
import jakarta.persistence.Temporal;
|
||||||
import jakarta.persistence.TemporalType;
|
import jakarta.persistence.TemporalType;
|
||||||
|
|
||||||
import org.hibernate.annotations.Fetch;
|
import org.hibernate.annotations.Fetch;
|
||||||
import org.hibernate.annotations.FetchMode;
|
import org.hibernate.annotations.FetchMode;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of RefreshTest.
|
* Implementation of RefreshTest.
|
||||||
|
@ -44,7 +43,6 @@ import static org.junit.Assert.assertEquals;
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class RefreshTest {
|
public class RefreshTest {
|
||||||
|
|
||||||
private JobBatch batch;
|
private JobBatch batch;
|
||||||
|
@ -67,11 +65,14 @@ public class RefreshTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testRefreshCascade(SessionFactoryScope scope) {
|
void testCannotRefreshCascadeDetachedEntity(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.refresh( batch );
|
assertThrows(IllegalArgumentException.class,
|
||||||
batch.jobs.forEach( job -> assertEquals( "Jobs not refreshed!", 1, job.status ) );
|
() -> session.refresh( batch ),
|
||||||
|
"Given entity is not associated with the persistence context"
|
||||||
|
);
|
||||||
|
batch.jobs.forEach( job -> assertEquals( 0, job.status ) );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,18 +6,16 @@ package org.hibernate.orm.test.collection.backref.map.compkey;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,7 +31,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class BackrefCompositeMapKeyTest {
|
public class BackrefCompositeMapKeyTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -114,7 +111,7 @@ public class BackrefCompositeMapKeyTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||||
Product prod = new Product( "Widget" );
|
Product prod = new Product( "Widget" );
|
||||||
MapKey mapKey = new MapKey( "Top" );
|
MapKey mapKey = new MapKey( "Top" );
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
|
@ -130,14 +127,16 @@ public class BackrefCompositeMapKeyTest {
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.lock( prod, LockMode.READ );
|
assertThrows(IllegalArgumentException.class,
|
||||||
prod.getParts().remove( mapKey );
|
() -> session.lock( prod, LockMode.READ ),
|
||||||
|
"Given entity is not associated with the persistence context"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
assertNull( session.get( Part.class, "Widge" ) );
|
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||||
assertNotNull( session.get( Part.class, "Get" ) );
|
assertNotNull( session.get( Part.class, "Get" ) );
|
||||||
session.remove( session.get( Product.class, "Widget" ) );
|
session.remove( session.get( Product.class, "Widget" ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -63,7 +63,6 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
||||||
protected void applySettings(StandardServiceRegistryBuilder builer) {
|
protected void applySettings(StandardServiceRegistryBuilder builer) {
|
||||||
builer.applySetting( Environment.GENERATE_STATISTICS, "true" );
|
builer.applySetting( Environment.GENERATE_STATISTICS, "true" );
|
||||||
builer.applySetting( Environment.STATEMENT_BATCH_SIZE, "0" );
|
builer.applySetting( Environment.STATEMENT_BATCH_SIZE, "0" );
|
||||||
builer.applySetting( Environment.ALLOW_REFRESH_DETACHED_ENTITY, "true" );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -365,18 +364,9 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
||||||
|
|
||||||
inTransaction(
|
inTransaction(
|
||||||
s -> {
|
s -> {
|
||||||
// refresh detached
|
Contract c = s.get(Contract.class, contract.getId());
|
||||||
s.refresh( contract );
|
c.setCustomerName( "joe" );
|
||||||
assertTrue( s.isReadOnly( contract ) );
|
s.merge( c );
|
||||||
assertEquals( "gavin", contract.getCustomerName() );
|
|
||||||
assertEquals( 2, contract.getVariations().size() );
|
|
||||||
Iterator<ContractVariation> it = contract.getVariations().iterator();
|
|
||||||
ContractVariation cv1 = it.next();
|
|
||||||
assertEquals( "expensive", cv1.getText() );
|
|
||||||
ContractVariation cv2 = it.next();
|
|
||||||
assertEquals( "more expensive", cv2.getText() );
|
|
||||||
assertTrue( s.isReadOnly( cv1 ) );
|
|
||||||
assertTrue( s.isReadOnly( cv2 ) );
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -384,15 +374,13 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
||||||
assertUpdateCount( 0 );
|
assertUpdateCount( 0 );
|
||||||
clearCounts();
|
clearCounts();
|
||||||
|
|
||||||
contract.setCustomerName( "joe" );
|
|
||||||
|
|
||||||
inTransaction(
|
inTransaction(
|
||||||
s -> {
|
s -> {
|
||||||
s.refresh( contract );
|
Contract c = s.get(Contract.class, contract.getId());
|
||||||
assertTrue( s.isReadOnly( contract ) );
|
assertTrue( s.isReadOnly( c ) );
|
||||||
assertEquals( "gavin", contract.getCustomerName() );
|
assertEquals( "gavin", c.getCustomerName() );
|
||||||
assertEquals( 2, contract.getVariations().size() );
|
assertEquals( 2, c.getVariations().size() );
|
||||||
Iterator<ContractVariation> it = contract.getVariations().iterator();
|
Iterator<ContractVariation> it = c.getVariations().iterator();
|
||||||
ContractVariation cv1 = it.next();
|
ContractVariation cv1 = it.next();
|
||||||
assertEquals( "expensive", cv1.getText() );
|
assertEquals( "expensive", cv1.getText() );
|
||||||
ContractVariation cv2 = it.next();
|
ContractVariation cv2 = it.next();
|
||||||
|
@ -401,11 +389,6 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
||||||
assertTrue( s.isReadOnly( cv2 ) );
|
assertTrue( s.isReadOnly( cv2 ) );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// refresh updated detached
|
|
||||||
|
|
||||||
assertInsertCount( 0 );
|
|
||||||
assertUpdateCount( 0 );
|
|
||||||
clearCounts();
|
|
||||||
|
|
||||||
inTransaction(
|
inTransaction(
|
||||||
s -> {
|
s -> {
|
||||||
|
|
|
@ -9,15 +9,12 @@ import java.util.Iterator;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.StaleObjectStateException;
|
import org.hibernate.StaleObjectStateException;
|
||||||
import org.hibernate.StaleStateException;
|
import org.hibernate.StaleStateException;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.metamodel.MappingMetamodel;
|
import org.hibernate.metamodel.MappingMetamodel;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -32,6 +29,7 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
|
@ -40,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
* @author Gail Badner
|
* @author Gail Badner
|
||||||
*/
|
*/
|
||||||
@SessionFactory(generateStatistics = true)
|
@SessionFactory(generateStatistics = true)
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public abstract class AbstractEntityWithManyToManyTest {
|
public abstract class AbstractEntityWithManyToManyTest {
|
||||||
private boolean isPlanContractsInverse;
|
private boolean isPlanContractsInverse;
|
||||||
private boolean isPlanContractsBidirectional;
|
private boolean isPlanContractsBidirectional;
|
||||||
|
@ -171,9 +168,12 @@ public abstract class AbstractEntityWithManyToManyTest {
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
s -> {
|
s -> {
|
||||||
s.lock( c, LockMode.NONE );
|
assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> s.lock( c, LockMode.NONE ),
|
||||||
|
"Given entity is not associated with the persistence context"
|
||||||
|
);
|
||||||
Plan p = new Plan( "plan" );
|
Plan p = new Plan( "plan" );
|
||||||
p.addContract( c );
|
p.addContract( s.get(Contract.class, c.getId()) );
|
||||||
s.persist( p );
|
s.persist( p );
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -12,12 +12,9 @@ import jakarta.persistence.criteria.Root;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -33,16 +30,15 @@ import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
xmlMappings = "org/hibernate/orm/test/joinedsubclass/Person.hbm.xml"
|
xmlMappings = "org/hibernate/orm/test/joinedsubclass/Person.hbm.xml"
|
||||||
)
|
)
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class JoinedSubclassTest {
|
public class JoinedSubclassTest {
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void tearDown(SessionFactoryScope scope) {
|
public void tearDown(SessionFactoryScope scope) {
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.createQuery( "delete from Employee" ).executeUpdate();
|
session.createMutationQuery( "delete from Employee" ).executeUpdate();
|
||||||
session.createQuery( "delete from Customer" ).executeUpdate();
|
session.createMutationQuery( "delete from Customer" ).executeUpdate();
|
||||||
session.createQuery( "delete from Person" ).executeUpdate();
|
session.createMutationQuery( "delete from Person" ).executeUpdate();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -63,15 +59,15 @@ public class JoinedSubclassTest {
|
||||||
|
|
||||||
Customer c = scope.fromTransaction(
|
Customer c = scope.fromTransaction(
|
||||||
session ->
|
session ->
|
||||||
session.get( Customer.class, new Long( e.getId() ) )
|
session.get( Customer.class, e.getId() )
|
||||||
|
|
||||||
);
|
);
|
||||||
assertNull( c );
|
assertNull( c );
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
Employee employee = session.get( Employee.class, new Long( e.getId() ) );
|
Employee employee = session.get( Employee.class, e.getId() );
|
||||||
Customer customer = session.get( Customer.class, new Long( e.getId() ) );
|
Customer customer = session.get( Customer.class, e.getId() );
|
||||||
assertNotNull( employee );
|
assertNotNull( employee );
|
||||||
assertNull( customer );
|
assertNull( customer );
|
||||||
}
|
}
|
||||||
|
@ -148,8 +144,8 @@ public class JoinedSubclassTest {
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.lock( p, LockMode.PESSIMISTIC_WRITE );
|
session.lock( session.get(Person.class, p.getId()), LockMode.PESSIMISTIC_WRITE );
|
||||||
session.lock( q, LockMode.PESSIMISTIC_WRITE );
|
session.lock( session.get( Employee.class, q.getId()), LockMode.PESSIMISTIC_WRITE );
|
||||||
session.remove( p );
|
session.remove( p );
|
||||||
session.remove( q );
|
session.remove( q );
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,15 +9,12 @@ import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.annotations.GenericGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.testing.orm.junit.Jpa;
|
import org.hibernate.testing.orm.junit.Jpa;
|
||||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
import org.junit.jupiter.api.AfterAll;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
@ -26,9 +23,16 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
@Jpa(annotatedClasses = {MergeWithTransientNonCascadedAssociationTest.Person.class,
|
@Jpa(annotatedClasses = {MergeWithTransientNonCascadedAssociationTest.Person.class,
|
||||||
MergeWithTransientNonCascadedAssociationTest.Address.class},
|
MergeWithTransientNonCascadedAssociationTest.Address.class})
|
||||||
properties = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class MergeWithTransientNonCascadedAssociationTest {
|
public class MergeWithTransientNonCascadedAssociationTest {
|
||||||
|
|
||||||
|
@AfterAll
|
||||||
|
public void tearDown(EntityManagerFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
entityManager -> entityManager.createQuery( "delete from Person" ).executeUpdate()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMergeWithTransientNonCascadedAssociation(EntityManagerFactoryScope scope) {
|
public void testMergeWithTransientNonCascadedAssociation(EntityManagerFactoryScope scope) {
|
||||||
Person person = new Person();
|
Person person = new Person();
|
||||||
|
@ -54,14 +58,6 @@ public class MergeWithTransientNonCascadedAssociationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
scope.inTransaction(
|
|
||||||
entityManager -> {
|
|
||||||
person.address = null;
|
|
||||||
entityManager.unwrap( Session.class ).lock( person, LockMode.NONE );
|
|
||||||
entityManager.unwrap( Session.class ).remove( person );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Entity(name = "Person")
|
@Entity(name = "Person")
|
||||||
|
|
|
@ -1,69 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.jpa.refresh;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
|
||||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
|
||||||
import org.hibernate.testing.orm.junit.Jpa;
|
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrea Boriero
|
|
||||||
*/
|
|
||||||
@JiraKey(value = "HHH-11188")
|
|
||||||
@Jpa(
|
|
||||||
annotatedClasses = {
|
|
||||||
TestEntity.class
|
|
||||||
},
|
|
||||||
integrationSettings = { @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true") }
|
|
||||||
)
|
|
||||||
public class RefreshDetachedInstanceWhenIsAllowedTest {
|
|
||||||
private TestEntity testEntity;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp(EntityManagerFactoryScope scope) {
|
|
||||||
testEntity = new TestEntity();
|
|
||||||
scope.inTransaction(
|
|
||||||
entityManager -> {
|
|
||||||
entityManager.persist( testEntity );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void tearDown(EntityManagerFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
entityManager -> {
|
|
||||||
entityManager.createQuery( "delete from TestEntity" ).executeUpdate();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUnwrappedSessionRefreshDetachedInstance(EntityManagerFactoryScope scope) {
|
|
||||||
scope.inEntityManager(
|
|
||||||
entityManager -> {
|
|
||||||
final Session session = entityManager.unwrap( Session.class );
|
|
||||||
session.refresh( testEntity );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRefreshDetachedInstance(EntityManagerFactoryScope scope) {
|
|
||||||
scope.inEntityManager(
|
|
||||||
entityManager -> {
|
|
||||||
entityManager.refresh( testEntity );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,73 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.jpa.refresh;
|
|
||||||
|
|
||||||
import org.hibernate.Session;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
|
||||||
import org.hibernate.testing.orm.junit.Jpa;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrea Boriero
|
|
||||||
*/
|
|
||||||
@Jpa(
|
|
||||||
annotatedClasses = {
|
|
||||||
TestEntity.class
|
|
||||||
}
|
|
||||||
)
|
|
||||||
public class RefreshDetachedInstanceWhenIsNotAllowedTest {
|
|
||||||
private TestEntity testEntity;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp(EntityManagerFactoryScope scope) {
|
|
||||||
testEntity = new TestEntity();
|
|
||||||
scope.inTransaction(
|
|
||||||
entityManager -> {
|
|
||||||
entityManager.persist( testEntity );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void tearDown(EntityManagerFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
entityManager -> {
|
|
||||||
entityManager.createQuery( "delete from TestEntity" ).executeUpdate();
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUnwrappedSessionRefreshDetachedInstance(EntityManagerFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
entityManager -> {
|
|
||||||
final Session session = entityManager.unwrap( Session.class );
|
|
||||||
Assertions.assertThrows(
|
|
||||||
IllegalArgumentException.class,
|
|
||||||
() -> session.refresh( testEntity ),
|
|
||||||
"Should have thrown an IllegalArgumentException"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRefreshDetachedInstance(EntityManagerFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
entityManager -> {
|
|
||||||
Assertions.assertThrows(
|
|
||||||
IllegalArgumentException.class,
|
|
||||||
() -> entityManager.refresh( testEntity ),
|
|
||||||
"Should have thrown an IllegalArgumentException"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.jpa.refresh;
|
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrea Boriero
|
|
||||||
*/
|
|
||||||
@Entity
|
|
||||||
public class TestEntity {
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
public long id;
|
|
||||||
}
|
|
|
@ -10,7 +10,6 @@ import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
|
|
||||||
|
|
||||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY;
|
|
||||||
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
||||||
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
|
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
|
||||||
import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYPE;
|
import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYPE;
|
||||||
|
@ -19,8 +18,7 @@ import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYP
|
||||||
settings = {
|
settings = {
|
||||||
@Setting( name = USE_SECOND_LEVEL_CACHE, value = "true" ),
|
@Setting( name = USE_SECOND_LEVEL_CACHE, value = "true" ),
|
||||||
@Setting( name = DEFAULT_ACCESSTYPE, value = "nonstrict-read-write" ),
|
@Setting( name = DEFAULT_ACCESSTYPE, value = "nonstrict-read-write" ),
|
||||||
@Setting( name = GENERATE_STATISTICS, value = "true" ),
|
@Setting( name = GENERATE_STATISTICS, value = "true" )
|
||||||
@Setting( name = ALLOW_REFRESH_DETACHED_ENTITY, value = "true" )
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@DomainModel( annotatedClasses = {A.class, Another.class, AllCached.class, B.class, SubClass.class} )
|
@DomainModel( annotatedClasses = {A.class, Another.class, AllCached.class, B.class, SubClass.class} )
|
||||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
import org.hibernate.testing.orm.junit.Setting;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY;
|
|
||||||
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
||||||
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
|
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
|
||||||
import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYPE;
|
import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYPE;
|
||||||
|
@ -28,8 +27,7 @@ import static org.junit.Assert.assertNull;
|
||||||
settings = {
|
settings = {
|
||||||
@Setting( name = USE_SECOND_LEVEL_CACHE, value = "true" ),
|
@Setting( name = USE_SECOND_LEVEL_CACHE, value = "true" ),
|
||||||
@Setting( name = DEFAULT_ACCESSTYPE, value = "nonstrict-read-write" ),
|
@Setting( name = DEFAULT_ACCESSTYPE, value = "nonstrict-read-write" ),
|
||||||
@Setting( name = GENERATE_STATISTICS, value = "true" ),
|
@Setting( name = GENERATE_STATISTICS, value = "true" )
|
||||||
@Setting( name = ALLOW_REFRESH_DETACHED_ENTITY, value = "true" )
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@DomainModel( annotatedClasses = {A.class, Another.class, AllCached.class, B.class, SubClass.class} )
|
@DomainModel( annotatedClasses = {A.class, Another.class, AllCached.class, B.class, SubClass.class} )
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.orm.test.mapping.naturalid.mutable.cached;
|
package org.hibernate.orm.test.mapping.naturalid.mutable.cached;
|
||||||
|
|
||||||
import org.hibernate.LockOptions;
|
|
||||||
import org.hibernate.cache.spi.CacheImplementor;
|
import org.hibernate.cache.spi.CacheImplementor;
|
||||||
import org.hibernate.internal.SessionFactoryImpl;
|
import org.hibernate.internal.SessionFactoryImpl;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
|
@ -274,38 +273,4 @@ public abstract class CachedMutableNaturalIdTest {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReattachUnmodifiedInstance(SessionFactoryScope scope) {
|
|
||||||
final B created = scope.fromTransaction(
|
|
||||||
(session) -> {
|
|
||||||
A a = new A();
|
|
||||||
B b = new B();
|
|
||||||
b.naturalid = 100;
|
|
||||||
session.persist( a );
|
|
||||||
session.persist( b );
|
|
||||||
b.assA = a;
|
|
||||||
a.assB.add( b );
|
|
||||||
|
|
||||||
return b;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
scope.inTransaction(
|
|
||||||
(session) -> {
|
|
||||||
// HHH-7513 failure during reattachment
|
|
||||||
session.lock( created, LockOptions.NONE );
|
|
||||||
session.remove( created.assA );
|
|
||||||
session.remove( created );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
scope.inTransaction(
|
|
||||||
(session) -> {
|
|
||||||
// true if the re-attachment worked
|
|
||||||
assertEquals( session.createQuery( "FROM A" ).list().size(), 0 );
|
|
||||||
assertEquals( session.createQuery( "FROM B" ).list().size(), 0 );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,19 +6,17 @@ package org.hibernate.orm.test.orphan;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -28,7 +26,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
xmlMappings = "org/hibernate/orm/test/orphan/Product.hbm.xml"
|
xmlMappings = "org/hibernate/orm/test/orphan/Product.hbm.xml"
|
||||||
)
|
)
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class OrphanTest {
|
public class OrphanTest {
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -138,7 +135,7 @@ public class OrphanTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||||
Product prod = new Product();
|
Product prod = new Product();
|
||||||
Part part = new Part();
|
Part part = new Part();
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
|
@ -158,14 +155,16 @@ public class OrphanTest {
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
session.lock( prod, LockMode.READ );
|
assertThrows(IllegalArgumentException.class,
|
||||||
prod.getParts().remove( part );
|
() -> session.lock( prod, LockMode.READ ),
|
||||||
|
"Given entity is not associated with the persistence context"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
scope.inTransaction(
|
scope.inTransaction(
|
||||||
session -> {
|
session -> {
|
||||||
assertNull( session.get( Part.class, "Widge" ) );
|
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||||
assertNotNull( session.get( Part.class, "Get" ) );
|
assertNotNull( session.get( Part.class, "Get" ) );
|
||||||
session.remove( session.get( Product.class, "Widget" ) );
|
session.remove( session.get( Product.class, "Widget" ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,13 @@ import org.hibernate.CacheMode;
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.Hibernate;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.UnresolvableObjectException;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.proxy.LazyInitializer;
|
import org.hibernate.proxy.LazyInitializer;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
@ -42,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
"org/hibernate/orm/test/readonly/TextHolder.hbm.xml"
|
"org/hibernate/orm/test/readonly/TextHolder.hbm.xml"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1156,9 +1151,9 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
||||||
s.flush();
|
s.flush();
|
||||||
try {
|
try {
|
||||||
s.refresh( dp );
|
s.refresh( dp );
|
||||||
fail( "should have thrown UnresolvableObjectException" );
|
fail( "should have thrown IllegalArgumentException" );
|
||||||
}
|
}
|
||||||
catch (UnresolvableObjectException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -1182,9 +1177,9 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
||||||
assertTrue( Hibernate.isInitialized( dpProxyInit ) );
|
assertTrue( Hibernate.isInitialized( dpProxyInit ) );
|
||||||
try {
|
try {
|
||||||
s.refresh( dpProxyInit );
|
s.refresh( dpProxyInit );
|
||||||
fail( "should have thrown UnresolvableObjectException" );
|
fail( "should have thrown IllegalArgumentException" );
|
||||||
}
|
}
|
||||||
catch (UnresolvableObjectException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -1199,9 +1194,9 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
||||||
s.refresh( dpProxy );
|
s.refresh( dpProxy );
|
||||||
assertFalse( Hibernate.isInitialized( dpProxy ) );
|
assertFalse( Hibernate.isInitialized( dpProxy ) );
|
||||||
Hibernate.initialize( dpProxy );
|
Hibernate.initialize( dpProxy );
|
||||||
fail( "should have thrown UnresolvableObjectException" );
|
fail( "should have thrown IllegalArgumentException" );
|
||||||
}
|
}
|
||||||
catch (UnresolvableObjectException ex) {
|
catch (IllegalArgumentException ex) {
|
||||||
// expected
|
// expected
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -1210,50 +1205,6 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadOnlyRefreshDetached(SessionFactoryScope scope) {
|
|
||||||
Session s = openSession( scope );
|
|
||||||
s.setCacheMode( CacheMode.IGNORE );
|
|
||||||
Transaction t = s.beginTransaction();
|
|
||||||
DataPoint dp = new DataPoint();
|
|
||||||
dp.setDescription( "original" );
|
|
||||||
dp.setX( new BigDecimal( 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
s.persist( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession( scope );
|
|
||||||
s.setCacheMode( CacheMode.IGNORE );
|
|
||||||
t = s.beginTransaction();
|
|
||||||
dp = s.getReference( DataPoint.class, dp.getId() );
|
|
||||||
assertFalse( Hibernate.isInitialized( dp ) );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
s.setReadOnly( dp, true );
|
|
||||||
assertTrue( s.isReadOnly( dp ) );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertTrue( Hibernate.isInitialized( dp ) );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
assertTrue( Hibernate.isInitialized( dp ) );
|
|
||||||
s.setReadOnly( dp, true );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
t.commit();
|
|
||||||
|
|
||||||
s.clear();
|
|
||||||
t = s.beginTransaction();
|
|
||||||
dp = s.get( DataPoint.class, dp.getId() );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
s.remove( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadOnlyProxyMergeDetachedProxyWithChange(SessionFactoryScope scope) {
|
public void testReadOnlyProxyMergeDetachedProxyWithChange(SessionFactoryScope scope) {
|
||||||
DataPoint dpOrig = createDataPoint( CacheMode.IGNORE, scope );
|
DataPoint dpOrig = createDataPoint( CacheMode.IGNORE, scope );
|
||||||
|
|
|
@ -13,14 +13,11 @@ import org.hibernate.ScrollMode;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
@ -39,7 +36,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
"org/hibernate/orm/test/readonly/TextHolder.hbm.xml"
|
"org/hibernate/orm/test/readonly/TextHolder.hbm.xml"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class ReadOnlySessionTest extends AbstractReadOnlyTest {
|
public class ReadOnlySessionTest extends AbstractReadOnlyTest {
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -450,53 +446,6 @@ public class ReadOnlySessionTest extends AbstractReadOnlyTest {
|
||||||
s.close();
|
s.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadOnlyRefreshDetached(SessionFactoryScope scope) {
|
|
||||||
Session s = openSession( scope );
|
|
||||||
s.setCacheMode( CacheMode.IGNORE );
|
|
||||||
Transaction t = s.beginTransaction();
|
|
||||||
DataPoint dp = new DataPoint();
|
|
||||||
dp.setDescription( "original" );
|
|
||||||
dp.setX( new BigDecimal( 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
s.persist( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession( scope );
|
|
||||||
s.setCacheMode( CacheMode.IGNORE );
|
|
||||||
t = s.beginTransaction();
|
|
||||||
s.setDefaultReadOnly( false );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
s.setDefaultReadOnly( true );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertTrue( s.isReadOnly( dp ) );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
t.commit();
|
|
||||||
|
|
||||||
s.clear();
|
|
||||||
t = s.beginTransaction();
|
|
||||||
dp = s.get( DataPoint.class, dp.getId() );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
s.remove( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadOnlyProxyRefresh(SessionFactoryScope scope) {
|
public void testReadOnlyProxyRefresh(SessionFactoryScope scope) {
|
||||||
Session s = openSession( scope );
|
Session s = openSession( scope );
|
||||||
|
@ -554,65 +503,6 @@ public class ReadOnlySessionTest extends AbstractReadOnlyTest {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadOnlyProxyRefreshDetached(SessionFactoryScope scope) {
|
|
||||||
Session s = openSession( scope );
|
|
||||||
s.setCacheMode( CacheMode.IGNORE );
|
|
||||||
Transaction t = s.beginTransaction();
|
|
||||||
DataPoint dp = new DataPoint();
|
|
||||||
dp.setDescription( "original" );
|
|
||||||
dp.setX( new BigDecimal( 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
s.persist( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
s = openSession( scope );
|
|
||||||
s.setCacheMode( CacheMode.IGNORE );
|
|
||||||
t = s.beginTransaction();
|
|
||||||
s.setDefaultReadOnly( true );
|
|
||||||
dp = (DataPoint) s.getReference( DataPoint.class, dp.getId() );
|
|
||||||
assertFalse( Hibernate.isInitialized( dp ) );
|
|
||||||
assertTrue( s.isReadOnly( dp ) );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertTrue( Hibernate.isInitialized( dp ) );
|
|
||||||
s.setDefaultReadOnly( false );
|
|
||||||
assertTrue( s.isReadOnly( dp ) );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertTrue( Hibernate.isInitialized( dp ) );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
assertFalse( s.isReadOnly( ( (HibernateProxy) dp ).getHibernateLazyInitializer().getImplementation() ) );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
assertTrue( Hibernate.isInitialized( dp ) );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
assertFalse( s.isReadOnly( ( (HibernateProxy) dp ).getHibernateLazyInitializer().getImplementation() ) );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
s.setDefaultReadOnly( true );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertTrue( s.isReadOnly( dp ) );
|
|
||||||
assertTrue( s.isReadOnly( ( (HibernateProxy) dp ).getHibernateLazyInitializer().getImplementation() ) );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
t.commit();
|
|
||||||
|
|
||||||
s.clear();
|
|
||||||
t = s.beginTransaction();
|
|
||||||
dp = s.get( DataPoint.class, dp.getId() );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
s.remove( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadOnlyDelete(SessionFactoryScope scope) {
|
public void testReadOnlyDelete(SessionFactoryScope scope) {
|
||||||
Session s = openSession( scope );
|
Session s = openSession( scope );
|
||||||
|
|
|
@ -13,11 +13,8 @@ import org.hibernate.ScrollableResults;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.Transaction;
|
import org.hibernate.Transaction;
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
@ -36,7 +33,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
"org/hibernate/orm/test/readonly/TextHolder.hbm.xml"
|
"org/hibernate/orm/test/readonly/TextHolder.hbm.xml"
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class ReadOnlyTest extends AbstractReadOnlyTest {
|
public class ReadOnlyTest extends AbstractReadOnlyTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -317,55 +313,6 @@ public class ReadOnlyTest extends AbstractReadOnlyTest {
|
||||||
clearCounts( scope );
|
clearCounts( scope );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testReadOnlyRefreshDetached(SessionFactoryScope scope) {
|
|
||||||
clearCounts( scope );
|
|
||||||
|
|
||||||
Session s = openSession( scope );
|
|
||||||
Transaction t = s.beginTransaction();
|
|
||||||
DataPoint dp = new DataPoint();
|
|
||||||
dp.setDescription( "original" );
|
|
||||||
dp.setX( new BigDecimal( 0.1d ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
dp.setY( new BigDecimal( Math.cos( dp.getX().doubleValue() ) ).setScale( 19, BigDecimal.ROUND_DOWN ) );
|
|
||||||
s.persist( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
assertInsertCount( 1, scope );
|
|
||||||
assertUpdateCount( 0, scope );
|
|
||||||
clearCounts( scope );
|
|
||||||
|
|
||||||
s = openSession( scope );
|
|
||||||
t = s.beginTransaction();
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
s.setReadOnly( dp, true );
|
|
||||||
dp.setDescription( "changed" );
|
|
||||||
assertEquals( "changed", dp.getDescription() );
|
|
||||||
s.evict( dp );
|
|
||||||
s.refresh( dp );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
assertFalse( s.isReadOnly( dp ) );
|
|
||||||
t.commit();
|
|
||||||
|
|
||||||
assertInsertCount( 0, scope );
|
|
||||||
assertUpdateCount( 0, scope );
|
|
||||||
|
|
||||||
s.clear();
|
|
||||||
t = s.beginTransaction();
|
|
||||||
dp = (DataPoint) s.get( DataPoint.class, dp.getId() );
|
|
||||||
assertEquals( "original", dp.getDescription() );
|
|
||||||
s.remove( dp );
|
|
||||||
t.commit();
|
|
||||||
s.close();
|
|
||||||
|
|
||||||
assertUpdateCount( 0, scope );
|
|
||||||
assertDeleteCount( 1, scope );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadOnlyDelete(SessionFactoryScope scope) {
|
public void testReadOnlyDelete(SessionFactoryScope scope) {
|
||||||
clearCounts( scope );
|
clearCounts( scope );
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.refresh;
|
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.orm.test.jpa.refresh.TestEntity;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrea Boriero
|
|
||||||
*/
|
|
||||||
@JiraKey(value = "HHH-11188")
|
|
||||||
@DomainModel(
|
|
||||||
annotatedClasses = TestEntity.class
|
|
||||||
)
|
|
||||||
@SessionFactory
|
|
||||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class RefreshDetachedInstanceWhenIsAllowedTest {
|
|
||||||
private TestEntity testEntity;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp(SessionFactoryScope scope) {
|
|
||||||
testEntity = new TestEntity();
|
|
||||||
scope.inTransaction(
|
|
||||||
session ->
|
|
||||||
session.persist( testEntity )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void tearDown(SessionFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
session ->
|
|
||||||
session.createQuery( "delete from TestEntity" ).executeUpdate()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRefreshDetachedInstance(SessionFactoryScope scope) {
|
|
||||||
scope.inSession(
|
|
||||||
session ->
|
|
||||||
session.refresh( testEntity )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,60 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.refresh;
|
|
||||||
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.orm.test.jpa.refresh.TestEntity;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
|
||||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.jupiter.api.AfterEach;
|
|
||||||
import org.junit.jupiter.api.Assertions;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Andrea Boriero
|
|
||||||
*/
|
|
||||||
@DomainModel(
|
|
||||||
annotatedClasses = TestEntity.class
|
|
||||||
)
|
|
||||||
@SessionFactory
|
|
||||||
@ServiceRegistry(
|
|
||||||
settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "false")
|
|
||||||
)
|
|
||||||
public class RefreshDetachedInstanceWhenIsNotAllowedTest {
|
|
||||||
private TestEntity testEntity;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
public void setUp(SessionFactoryScope scope) {
|
|
||||||
testEntity = new TestEntity();
|
|
||||||
scope.inTransaction(
|
|
||||||
session ->
|
|
||||||
session.persist( testEntity )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterEach
|
|
||||||
public void tearDown(SessionFactoryScope scope) {
|
|
||||||
scope.inTransaction(
|
|
||||||
session ->
|
|
||||||
session.createQuery( "delete from TestEntity" ).executeUpdate()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRefreshDetachedInstance(SessionFactoryScope scope) {
|
|
||||||
scope.inSession(
|
|
||||||
session ->
|
|
||||||
Assertions.assertThrows(
|
|
||||||
IllegalArgumentException.class, () ->
|
|
||||||
session.refresh( testEntity )
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,140 +0,0 @@
|
||||||
/*
|
|
||||||
* SPDX-License-Identifier: LGPL-2.1-or-later
|
|
||||||
* Copyright Red Hat Inc. and Hibernate Authors
|
|
||||||
*/
|
|
||||||
package org.hibernate.orm.test.session;
|
|
||||||
|
|
||||||
import jakarta.persistence.Entity;
|
|
||||||
import jakarta.persistence.FetchType;
|
|
||||||
import jakarta.persistence.GeneratedValue;
|
|
||||||
import jakarta.persistence.Id;
|
|
||||||
import jakarta.persistence.ManyToOne;
|
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
|
||||||
import org.hibernate.proxy.AbstractLazyInitializer;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.JiraKey;
|
|
||||||
import org.hibernate.testing.logger.LoggerInspectionRule;
|
|
||||||
import org.hibernate.testing.logger.Triggerable;
|
|
||||||
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
|
|
||||||
import org.hibernate.testing.orm.junit.Jpa;
|
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
|
||||||
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.fail;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Vlad Mihalcea
|
|
||||||
*/
|
|
||||||
@Jpa(annotatedClasses = {AssociateEntityWithTwoSessionsTest.Location.class,
|
|
||||||
AssociateEntityWithTwoSessionsTest.Event.class},
|
|
||||||
properties = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
|
||||||
public class AssociateEntityWithTwoSessionsTest {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public LoggerInspectionRule logInspection = new LoggerInspectionRule(
|
|
||||||
Logger.getMessageLogger( MethodHandles.lookup(), CoreMessageLogger.class, AbstractLazyInitializer.class.getName() ) );
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@JiraKey( value = "HHH-12216" )
|
|
||||||
public void test(EntityManagerFactoryScope scope) {
|
|
||||||
|
|
||||||
final Location location = new Location();
|
|
||||||
location.setCity( "Cluj" );
|
|
||||||
|
|
||||||
final Event event = new Event();
|
|
||||||
event.setLocation( location );
|
|
||||||
|
|
||||||
scope.inTransaction( entityManager -> {
|
|
||||||
entityManager.persist( location );
|
|
||||||
entityManager.persist( event );
|
|
||||||
} );
|
|
||||||
|
|
||||||
final Triggerable triggerable = logInspection.watchForLogMessages( "HHH000485" );
|
|
||||||
triggerable.reset();
|
|
||||||
|
|
||||||
scope.inTransaction( entityManager -> {
|
|
||||||
Event e = entityManager.find( Event.class, event.id );
|
|
||||||
Location location1 = e.getLocation();
|
|
||||||
|
|
||||||
try {
|
|
||||||
scope.inTransaction( _entityManager -> {
|
|
||||||
_entityManager.unwrap( Session.class ).lock( location1, LockMode.NONE );
|
|
||||||
} );
|
|
||||||
|
|
||||||
fail("Should have thrown a HibernateException");
|
|
||||||
}
|
|
||||||
catch (Exception expected) {
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
|
|
||||||
assertEquals(
|
|
||||||
"HHH000485: Illegally attempted to associate a proxy for entity [org.hibernate.orm.test.session.AssociateEntityWithTwoSessionsTest$Location] with id [1] with two open sessions.",
|
|
||||||
triggerable.triggerMessage()
|
|
||||||
);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Location")
|
|
||||||
public static class Location {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
public Long id;
|
|
||||||
|
|
||||||
public String city;
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCity() {
|
|
||||||
return city;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCity(String city) {
|
|
||||||
this.city = city;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Entity(name = "Event")
|
|
||||||
public static class Event {
|
|
||||||
|
|
||||||
@Id
|
|
||||||
@GeneratedValue
|
|
||||||
public Long id;
|
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
|
||||||
private Location location;
|
|
||||||
|
|
||||||
public Long getId() {
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setId(Long id) {
|
|
||||||
this.id = id;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Location getLocation() {
|
|
||||||
return location;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setLocation(Location location) {
|
|
||||||
this.location = location;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -6,14 +6,11 @@ package org.hibernate.orm.test.sql.ast;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
|
||||||
import org.hibernate.annotations.Filter;
|
import org.hibernate.annotations.Filter;
|
||||||
import org.hibernate.annotations.FilterDef;
|
import org.hibernate.annotations.FilterDef;
|
||||||
import org.hibernate.annotations.ParamDef;
|
import org.hibernate.annotations.ParamDef;
|
||||||
import org.hibernate.cfg.AvailableSettings;
|
|
||||||
import org.hibernate.dialect.H2Dialect;
|
import org.hibernate.dialect.H2Dialect;
|
||||||
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||||
import org.hibernate.testing.orm.junit.Setting;
|
|
||||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||||
|
|
||||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||||
|
@ -45,8 +42,8 @@ import static org.hibernate.internal.util.StringHelper.*;
|
||||||
*/
|
*/
|
||||||
@ServiceRegistry( services = @ServiceRegistry.Service(
|
@ServiceRegistry( services = @ServiceRegistry.Service(
|
||||||
role = ParameterMarkerStrategy.class,
|
role = ParameterMarkerStrategy.class,
|
||||||
impl = ParameterMarkerStrategyTests.ParameterMarkerStrategyImpl.class
|
impl = ParameterMarkerStrategyTests.ParameterMarkerStrategyImpl.class )
|
||||||
), settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true") )
|
)
|
||||||
@DomainModel( annotatedClasses = {
|
@DomainModel( annotatedClasses = {
|
||||||
EntityOfBasics.class,
|
EntityOfBasics.class,
|
||||||
ParameterMarkerStrategyTests.EntityWithFilters.class,
|
ParameterMarkerStrategyTests.EntityWithFilters.class,
|
||||||
|
@ -127,28 +124,6 @@ public class ParameterMarkerStrategyTests {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
@Jira( "https://hibernate.atlassian.net/browse/HHH-16229" )
|
|
||||||
public void testLocking(SessionFactoryScope scope) {
|
|
||||||
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
|
|
||||||
|
|
||||||
final EntityWithVersion created = scope.fromTransaction( (session) -> {
|
|
||||||
final EntityWithVersion entity = new EntityWithVersion( 1, "Entity Prime" );
|
|
||||||
session.persist( entity );
|
|
||||||
return entity;
|
|
||||||
} );
|
|
||||||
|
|
||||||
statementInspector.clear();
|
|
||||||
scope.inTransaction( (session) -> {
|
|
||||||
session.lock( created, LockMode.PESSIMISTIC_FORCE_INCREMENT );
|
|
||||||
assertThat( statementInspector.getSqlQueries() ).hasSize( 1 );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?1" );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?2" );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).contains( "?3" );
|
|
||||||
assertThat( statementInspector.getSqlQueries().get( 0 ) ).matches( (sql) -> count( sql, "?" ) == 3 );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected
|
@FailureExpected
|
||||||
@Jira( "https://hibernate.atlassian.net/browse/HHH-16283" )
|
@Jira( "https://hibernate.atlassian.net/browse/HHH-16283" )
|
||||||
|
|
|
@ -245,6 +245,16 @@ parent.addChild( merged );
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
||||||
|
[[refresh-lock-deteached]]
|
||||||
|
== Refreshing/locking detached entities
|
||||||
|
|
||||||
|
Traditionally, Hibernate allowed detached entities to be refreshed. However, Jakarta Persistence prohibits this practice and specifies that an `IllegalArgumentException` should be thrown instead. Hibernate now fully aligns with the JPA specification in this regard.
|
||||||
|
|
||||||
|
Along the same line of thought, also acquiring a lock on a detached entity is no longer allowed.
|
||||||
|
|
||||||
|
To this effect the `hibernate.allow_refresh_detached_entity`, which allowed Hibernate's legacy refresh behaviour to be invoked, has been removed.
|
||||||
|
|
||||||
|
|
||||||
[[auto-cascade-persist]]
|
[[auto-cascade-persist]]
|
||||||
== Cascading persistence for `@Id` and `@MapsId` fields
|
== Cascading persistence for `@Id` and `@MapsId` fields
|
||||||
|
|
||||||
|
@ -377,6 +387,7 @@ While most users will never see this change, it might impact integrations which
|
||||||
|
|
||||||
* Settings
|
* Settings
|
||||||
** Removed `hibernate.mapping.precedence` and friends
|
** Removed `hibernate.mapping.precedence` and friends
|
||||||
|
** Removed `hibernate.allow_refresh_detached_entity`
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue