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]
|
||||
====
|
||||
Traditionally, Hibernate allowed detached entities to be refreshed.
|
||||
Unfortunately, Jakarta Persistence prohibits this practice and specifies that an `IllegalArgumentException` should be thrown instead.
|
||||
|
||||
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.
|
||||
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.
|
||||
====
|
||||
|
||||
[[pc-refresh-gotchas]]
|
||||
|
|
|
@ -426,11 +426,6 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableRefreshDetachedEntity() {
|
||||
this.optionsBuilder.disableRefreshDetachedEntity();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disableJtaTransactionAccess() {
|
||||
this.optionsBuilder.disableJtaTransactionAccess();
|
||||
|
|
|
@ -75,7 +75,6 @@ import org.hibernate.type.format.jaxb.JaxbXmlFormatMapper;
|
|||
import jakarta.persistence.criteria.Nulls;
|
||||
|
||||
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.AUTO_CLOSE_SESSION;
|
||||
import static org.hibernate.cfg.AvailableSettings.AUTO_EVICT_COLLECTION_CACHE;
|
||||
|
@ -176,7 +175,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
private boolean jtaTransactionAccessEnabled;
|
||||
private boolean allowOutOfTransactionUpdateOperations;
|
||||
private boolean releaseResourcesOnCloseEnabled;
|
||||
private boolean allowRefreshDetachedEntity;
|
||||
|
||||
// (JTA) transaction handling
|
||||
private boolean jtaTrackByThread;
|
||||
|
@ -335,12 +333,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
true
|
||||
);
|
||||
|
||||
this.allowRefreshDetachedEntity = configurationService.getSetting(
|
||||
ALLOW_REFRESH_DETACHED_ENTITY,
|
||||
BOOLEAN,
|
||||
false
|
||||
);
|
||||
|
||||
this.flushBeforeCompletionEnabled = configurationService.getSetting( FLUSH_BEFORE_COMPLETION, BOOLEAN, true );
|
||||
this.autoCloseSessionEnabled = configurationService.getSetting( AUTO_CLOSE_SESSION, BOOLEAN, false );
|
||||
|
||||
|
@ -906,11 +898,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return jtaTransactionAccessEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowRefreshDetachedEntity() {
|
||||
return allowRefreshDetachedEntity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAllowOutOfTransactionUpdateOperations() {
|
||||
return allowOutOfTransactionUpdateOperations;
|
||||
|
@ -1624,10 +1611,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
this.collectionsInDefaultFetchGroupEnabled = enabled;
|
||||
}
|
||||
|
||||
public void disableRefreshDetachedEntity() {
|
||||
this.allowRefreshDetachedEntity = false;
|
||||
}
|
||||
|
||||
public void disableJtaTransactionAccess() {
|
||||
this.jtaTransactionAccessEnabled = false;
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ import org.hibernate.type.format.FormatMapper;
|
|||
|
||||
import jakarta.persistence.criteria.Nulls;
|
||||
|
||||
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
|
||||
|
||||
/**
|
||||
* Convenience base class for custom implementations of {@link SessionFactoryOptions}
|
||||
* using delegation.
|
||||
|
@ -77,8 +79,13 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
return delegate.isJtaTransactionAccessEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated with no replacement.
|
||||
*/
|
||||
@Deprecated(since = "7.0", forRemoval = true)
|
||||
@Override
|
||||
public boolean isAllowRefreshDetachedEntity() {
|
||||
DEPRECATION_LOGGER.deprecatedRefreshLockDetachedEntity();
|
||||
return delegate.isAllowRefreshDetachedEntity();
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
package org.hibernate.boot.spi;
|
||||
|
||||
import org.hibernate.boot.SessionFactoryBuilder;
|
||||
import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER;
|
||||
|
||||
/**
|
||||
* Additional SPI contract for {@link SessionFactoryBuilder}, mainly intended for
|
||||
|
@ -21,10 +22,11 @@ public interface SessionFactoryBuilderImplementor extends SessionFactoryBuilder
|
|||
void disableJtaTransactionAccess();
|
||||
|
||||
/**
|
||||
* Called if {@link org.hibernate.cfg.AvailableSettings#ALLOW_REFRESH_DETACHED_ENTITY}
|
||||
* is not enabled.
|
||||
* @deprecated with no replacement.
|
||||
*/
|
||||
@Deprecated(since = "7.0", forRemoval = true)
|
||||
default void disableRefreshDetachedEntity() {
|
||||
DEPRECATION_LOGGER.deprecatedRefreshLockDetachedEntity();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,8 @@ import org.hibernate.type.format.FormatMapper;
|
|||
|
||||
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}.
|
||||
*
|
||||
|
@ -76,7 +78,12 @@ public interface SessionFactoryOptions extends QueryEngineOptions {
|
|||
|
||||
boolean isJtaTransactionAccessEnabled();
|
||||
|
||||
/**
|
||||
* @deprecated with no replacement.
|
||||
*/
|
||||
@Deprecated(since = "7.0", forRemoval = true)
|
||||
default boolean isAllowRefreshDetachedEntity() {
|
||||
DEPRECATION_LOGGER.deprecatedRefreshLockDetachedEntity();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -120,24 +120,6 @@ public interface AvailableSettings
|
|||
*/
|
||||
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
|
||||
* 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) {
|
||||
if ( !getSessionFactory().getSessionFactoryOptions().isAllowRefreshDetachedEntity() ) {
|
||||
if ( !managed( entityName, entity ) ) {
|
||||
throw new IllegalArgumentException( "Given entity is not associated with the persistence context" );
|
||||
}
|
||||
if ( !managed( entityName, entity ) ) {
|
||||
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."
|
||||
)
|
||||
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 );
|
||||
// }
|
||||
handleAllowJtaTransactionAccess( builder );
|
||||
handleAllowDetachedEntity( builder );
|
||||
addConfiguredSessionFactoryObserver( builder );
|
||||
builder.addSessionFactoryObservers( ServiceRegistryCloser.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
|
||||
private void handleAllowJtaTransactionAccess(SessionFactoryBuilder builder) {
|
||||
final boolean jtaTransactionAccessEnabled =
|
||||
|
|
|
@ -5,15 +5,13 @@
|
|||
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.assertThrows;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.bytecode.enhancement.extension.BytecodeEnhanced;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
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.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
@ -34,7 +32,6 @@ import java.util.Set;
|
|||
)
|
||||
@SessionFactory
|
||||
@BytecodeEnhanced
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class UnexpectedDeleteTest2 {
|
||||
|
||||
private Bar myBar;
|
||||
|
@ -59,8 +56,10 @@ public class UnexpectedDeleteTest2 {
|
|||
@Test
|
||||
public void test(SessionFactoryScope scope) {
|
||||
scope.inTransaction( s -> {
|
||||
s.refresh( myBar );
|
||||
assertFalse( myBar.foos.isEmpty() );
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> 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
|
||||
} );
|
||||
|
|
|
@ -6,7 +6,6 @@ package org.hibernate.orm.test.bytecode.enhancement.lazy.backref;
|
|||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.orm.test.bytecode.enhancement.lazy.NoDirtyCheckingContext;
|
||||
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.extension.BytecodeEnhanced;
|
||||
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.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
|
@ -42,7 +40,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
@SessionFactory
|
||||
@BytecodeEnhanced
|
||||
@CustomEnhancementContext({ NoDirtyCheckingContext.class, DirtyCheckEnhancementContext.class })
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class BackrefCompositeMapKeyTest {
|
||||
|
||||
@Test
|
||||
|
@ -123,7 +120,7 @@ public class BackrefCompositeMapKeyTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
||||
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||
Product prod = new Product( "Widget" );
|
||||
MapKey mapKey = new MapKey( "Top" );
|
||||
scope.inTransaction(
|
||||
|
@ -139,14 +136,16 @@ public class BackrefCompositeMapKeyTest {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.lock( prod, LockMode.READ );
|
||||
prod.getParts().remove( mapKey );
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> session.lock( prod, LockMode.READ ),
|
||||
"Given entity is not associated with the persistence context"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Get" ) );
|
||||
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.LockMode;
|
||||
import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.internal.util.SerializationHelper;
|
||||
import org.hibernate.orm.test.orphan.Part;
|
||||
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.orm.junit.DomainModel;
|
||||
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.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
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
|
||||
DefaultEnhancementContext.class
|
||||
})
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class OrphanTest {
|
||||
|
||||
@AfterEach
|
||||
|
@ -152,7 +149,7 @@ public class OrphanTest {
|
|||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
||||
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||
Product prod = new Product();
|
||||
Part part = new Part();
|
||||
scope.inTransaction(
|
||||
|
@ -172,14 +169,16 @@ public class OrphanTest {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.lock( prod, LockMode.READ );
|
||||
prod.getParts().remove( part );
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> session.lock( prod, LockMode.READ ),
|
||||
"Given entity is not associated with the persistence context"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Get" ) );
|
||||
session.remove( session.get( Product.class, "Widget" ) );
|
||||
}
|
||||
|
|
|
@ -19,18 +19,17 @@ import jakarta.persistence.OneToMany;
|
|||
import jakarta.persistence.Table;
|
||||
import jakarta.persistence.Temporal;
|
||||
import jakarta.persistence.TemporalType;
|
||||
|
||||
import org.hibernate.annotations.Fetch;
|
||||
import org.hibernate.annotations.FetchMode;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
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.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
|
||||
/**
|
||||
* Implementation of RefreshTest.
|
||||
|
@ -44,7 +43,6 @@ import static org.junit.Assert.assertEquals;
|
|||
}
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class RefreshTest {
|
||||
|
||||
private JobBatch batch;
|
||||
|
@ -67,11 +65,14 @@ public class RefreshTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
void testRefreshCascade(SessionFactoryScope scope) {
|
||||
void testCannotRefreshCascadeDetachedEntity(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.refresh( batch );
|
||||
batch.jobs.forEach( job -> assertEquals( "Jobs not refreshed!", 1, job.status ) );
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> 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.LockMode;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
||||
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.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
|
||||
|
@ -33,7 +31,6 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
|
|||
)
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class BackrefCompositeMapKeyTest {
|
||||
|
||||
@Test
|
||||
|
@ -114,7 +111,7 @@ public class BackrefCompositeMapKeyTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
||||
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||
Product prod = new Product( "Widget" );
|
||||
MapKey mapKey = new MapKey( "Top" );
|
||||
scope.inTransaction(
|
||||
|
@ -130,14 +127,16 @@ public class BackrefCompositeMapKeyTest {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.lock( prod, LockMode.READ );
|
||||
prod.getParts().remove( mapKey );
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> session.lock( prod, LockMode.READ ),
|
||||
"Given entity is not associated with the persistence context"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Get" ) );
|
||||
session.remove( session.get( Product.class, "Widget" ) );
|
||||
}
|
||||
|
|
|
@ -63,7 +63,6 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
|||
protected void applySettings(StandardServiceRegistryBuilder builer) {
|
||||
builer.applySetting( Environment.GENERATE_STATISTICS, "true" );
|
||||
builer.applySetting( Environment.STATEMENT_BATCH_SIZE, "0" );
|
||||
builer.applySetting( Environment.ALLOW_REFRESH_DETACHED_ENTITY, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -365,18 +364,9 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
|||
|
||||
inTransaction(
|
||||
s -> {
|
||||
// refresh detached
|
||||
s.refresh( contract );
|
||||
assertTrue( s.isReadOnly( contract ) );
|
||||
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 ) );
|
||||
Contract c = s.get(Contract.class, contract.getId());
|
||||
c.setCustomerName( "joe" );
|
||||
s.merge( c );
|
||||
}
|
||||
);
|
||||
|
||||
|
@ -384,15 +374,13 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
|||
assertUpdateCount( 0 );
|
||||
clearCounts();
|
||||
|
||||
contract.setCustomerName( "joe" );
|
||||
|
||||
inTransaction(
|
||||
s -> {
|
||||
s.refresh( contract );
|
||||
assertTrue( s.isReadOnly( contract ) );
|
||||
assertEquals( "gavin", contract.getCustomerName() );
|
||||
assertEquals( 2, contract.getVariations().size() );
|
||||
Iterator<ContractVariation> it = contract.getVariations().iterator();
|
||||
Contract c = s.get(Contract.class, contract.getId());
|
||||
assertTrue( s.isReadOnly( c ) );
|
||||
assertEquals( "gavin", c.getCustomerName() );
|
||||
assertEquals( 2, c.getVariations().size() );
|
||||
Iterator<ContractVariation> it = c.getVariations().iterator();
|
||||
ContractVariation cv1 = it.next();
|
||||
assertEquals( "expensive", cv1.getText() );
|
||||
ContractVariation cv2 = it.next();
|
||||
|
@ -401,11 +389,6 @@ public class ImmutableTest extends BaseSessionFactoryFunctionalTest {
|
|||
assertTrue( s.isReadOnly( cv2 ) );
|
||||
}
|
||||
);
|
||||
// refresh updated detached
|
||||
|
||||
assertInsertCount( 0 );
|
||||
assertUpdateCount( 0 );
|
||||
clearCounts();
|
||||
|
||||
inTransaction(
|
||||
s -> {
|
||||
|
|
|
@ -9,15 +9,12 @@ import java.util.Iterator;
|
|||
import org.hibernate.LockMode;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
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.SessionFactoryScope;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
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.assertNull;
|
||||
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.fail;
|
||||
|
||||
|
@ -40,7 +38,6 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
* @author Gail Badner
|
||||
*/
|
||||
@SessionFactory(generateStatistics = true)
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public abstract class AbstractEntityWithManyToManyTest {
|
||||
private boolean isPlanContractsInverse;
|
||||
private boolean isPlanContractsBidirectional;
|
||||
|
@ -171,9 +168,12 @@ public abstract class AbstractEntityWithManyToManyTest {
|
|||
|
||||
scope.inTransaction(
|
||||
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" );
|
||||
p.addContract( c );
|
||||
p.addContract( s.get(Contract.class, c.getId()) );
|
||||
s.persist( p );
|
||||
}
|
||||
);
|
||||
|
|
|
@ -12,12 +12,9 @@ import jakarta.persistence.criteria.Root;
|
|||
|
||||
import org.hibernate.LockMode;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
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.Test;
|
||||
|
||||
|
@ -33,16 +30,15 @@ import static org.junit.jupiter.api.Assertions.assertSame;
|
|||
xmlMappings = "org/hibernate/orm/test/joinedsubclass/Person.hbm.xml"
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class JoinedSubclassTest {
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||
session.createQuery( "delete from Customer" ).executeUpdate();
|
||||
session.createQuery( "delete from Person" ).executeUpdate();
|
||||
session.createMutationQuery( "delete from Employee" ).executeUpdate();
|
||||
session.createMutationQuery( "delete from Customer" ).executeUpdate();
|
||||
session.createMutationQuery( "delete from Person" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -63,15 +59,15 @@ public class JoinedSubclassTest {
|
|||
|
||||
Customer c = scope.fromTransaction(
|
||||
session ->
|
||||
session.get( Customer.class, new Long( e.getId() ) )
|
||||
session.get( Customer.class, e.getId() )
|
||||
|
||||
);
|
||||
assertNull( c );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Employee employee = session.get( Employee.class, new Long( e.getId() ) );
|
||||
Customer customer = session.get( Customer.class, new Long( e.getId() ) );
|
||||
Employee employee = session.get( Employee.class, e.getId() );
|
||||
Customer customer = session.get( Customer.class, e.getId() );
|
||||
assertNotNull( employee );
|
||||
assertNull( customer );
|
||||
}
|
||||
|
@ -148,8 +144,8 @@ public class JoinedSubclassTest {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.lock( p, LockMode.PESSIMISTIC_WRITE );
|
||||
session.lock( q, LockMode.PESSIMISTIC_WRITE );
|
||||
session.lock( session.get(Person.class, p.getId()), LockMode.PESSIMISTIC_WRITE );
|
||||
session.lock( session.get( Employee.class, q.getId()), LockMode.PESSIMISTIC_WRITE );
|
||||
session.remove( p );
|
||||
session.remove( q );
|
||||
}
|
||||
|
|
|
@ -9,15 +9,12 @@ import jakarta.persistence.GeneratedValue;
|
|||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.ManyToOne;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.testing.orm.junit.Jpa;
|
||||
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 static org.junit.jupiter.api.Assertions.fail;
|
||||
|
@ -26,9 +23,16 @@ import static org.junit.jupiter.api.Assertions.fail;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@Jpa(annotatedClasses = {MergeWithTransientNonCascadedAssociationTest.Person.class,
|
||||
MergeWithTransientNonCascadedAssociationTest.Address.class},
|
||||
properties = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
MergeWithTransientNonCascadedAssociationTest.Address.class})
|
||||
public class MergeWithTransientNonCascadedAssociationTest {
|
||||
|
||||
@AfterAll
|
||||
public void tearDown(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
entityManager -> entityManager.createQuery( "delete from Person" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMergeWithTransientNonCascadedAssociation(EntityManagerFactoryScope scope) {
|
||||
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")
|
||||
|
|
|
@ -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 static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY;
|
||||
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
|
||||
import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYPE;
|
||||
|
@ -19,8 +18,7 @@ import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYP
|
|||
settings = {
|
||||
@Setting( name = USE_SECOND_LEVEL_CACHE, value = "true" ),
|
||||
@Setting( name = DEFAULT_ACCESSTYPE, value = "nonstrict-read-write" ),
|
||||
@Setting( name = GENERATE_STATISTICS, value = "true" ),
|
||||
@Setting( name = ALLOW_REFRESH_DETACHED_ENTITY, value = "true" )
|
||||
@Setting( name = GENERATE_STATISTICS, value = "true" )
|
||||
}
|
||||
)
|
||||
@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.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.USE_SECOND_LEVEL_CACHE;
|
||||
import static org.hibernate.testing.cache.CachingRegionFactory.DEFAULT_ACCESSTYPE;
|
||||
|
@ -28,8 +27,7 @@ import static org.junit.Assert.assertNull;
|
|||
settings = {
|
||||
@Setting( name = USE_SECOND_LEVEL_CACHE, value = "true" ),
|
||||
@Setting( name = DEFAULT_ACCESSTYPE, value = "nonstrict-read-write" ),
|
||||
@Setting( name = GENERATE_STATISTICS, value = "true" ),
|
||||
@Setting( name = ALLOW_REFRESH_DETACHED_ENTITY, value = "true" )
|
||||
@Setting( name = GENERATE_STATISTICS, value = "true" )
|
||||
}
|
||||
)
|
||||
@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;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.cache.spi.CacheImplementor;
|
||||
import org.hibernate.internal.SessionFactoryImpl;
|
||||
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.LockMode;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
|
||||
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.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
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"
|
||||
)
|
||||
@SessionFactory
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class OrphanTest {
|
||||
|
||||
@AfterEach
|
||||
|
@ -138,7 +135,7 @@ public class OrphanTest {
|
|||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testOrphanDeleteAfterLock(SessionFactoryScope scope) {
|
||||
public void testCannotLockDetachedEntity(SessionFactoryScope scope) {
|
||||
Product prod = new Product();
|
||||
Part part = new Part();
|
||||
scope.inTransaction(
|
||||
|
@ -158,14 +155,16 @@ public class OrphanTest {
|
|||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.lock( prod, LockMode.READ );
|
||||
prod.getParts().remove( part );
|
||||
assertThrows(IllegalArgumentException.class,
|
||||
() -> session.lock( prod, LockMode.READ ),
|
||||
"Given entity is not associated with the persistence context"
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
assertNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Widge" ) );
|
||||
assertNotNull( session.get( Part.class, "Get" ) );
|
||||
session.remove( session.get( Product.class, "Widget" ) );
|
||||
}
|
||||
|
|
|
@ -10,17 +10,13 @@ import org.hibernate.CacheMode;
|
|||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.UnresolvableObjectException;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.LazyInitializer;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
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.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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"
|
||||
}
|
||||
)
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
||||
|
||||
@Test
|
||||
|
@ -1156,9 +1151,9 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
|||
s.flush();
|
||||
try {
|
||||
s.refresh( dp );
|
||||
fail( "should have thrown UnresolvableObjectException" );
|
||||
fail( "should have thrown IllegalArgumentException" );
|
||||
}
|
||||
catch (UnresolvableObjectException ex) {
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
finally {
|
||||
|
@ -1182,9 +1177,9 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
|||
assertTrue( Hibernate.isInitialized( dpProxyInit ) );
|
||||
try {
|
||||
s.refresh( dpProxyInit );
|
||||
fail( "should have thrown UnresolvableObjectException" );
|
||||
fail( "should have thrown IllegalArgumentException" );
|
||||
}
|
||||
catch (UnresolvableObjectException ex) {
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
finally {
|
||||
|
@ -1199,9 +1194,9 @@ public class ReadOnlyProxyTest extends AbstractReadOnlyTest {
|
|||
s.refresh( dpProxy );
|
||||
assertFalse( Hibernate.isInitialized( dpProxy ) );
|
||||
Hibernate.initialize( dpProxy );
|
||||
fail( "should have thrown UnresolvableObjectException" );
|
||||
fail( "should have thrown IllegalArgumentException" );
|
||||
}
|
||||
catch (UnresolvableObjectException ex) {
|
||||
catch (IllegalArgumentException ex) {
|
||||
// expected
|
||||
}
|
||||
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
|
||||
public void testReadOnlyProxyMergeDetachedProxyWithChange(SessionFactoryScope scope) {
|
||||
DataPoint dpOrig = createDataPoint( CacheMode.IGNORE, scope );
|
||||
|
|
|
@ -13,14 +13,11 @@ import org.hibernate.ScrollMode;
|
|||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
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.Setting;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
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"
|
||||
}
|
||||
)
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class ReadOnlySessionTest extends AbstractReadOnlyTest {
|
||||
|
||||
@AfterEach
|
||||
|
@ -450,53 +446,6 @@ public class ReadOnlySessionTest extends AbstractReadOnlyTest {
|
|||
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
|
||||
public void testReadOnlyProxyRefresh(SessionFactoryScope 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
|
||||
public void testReadOnlyDelete(SessionFactoryScope scope) {
|
||||
Session s = openSession( scope );
|
||||
|
|
|
@ -13,11 +13,8 @@ import org.hibernate.ScrollableResults;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
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.Setting;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
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"
|
||||
}
|
||||
)
|
||||
@ServiceRegistry(settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true"))
|
||||
public class ReadOnlyTest extends AbstractReadOnlyTest {
|
||||
|
||||
@Test
|
||||
|
@ -317,55 +313,6 @@ public class ReadOnlyTest extends AbstractReadOnlyTest {
|
|||
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
|
||||
public void testReadOnlyDelete(SessionFactoryScope 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 org.hibernate.LockMode;
|
||||
import org.hibernate.annotations.Filter;
|
||||
import org.hibernate.annotations.FilterDef;
|
||||
import org.hibernate.annotations.ParamDef;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.sql.ast.spi.ParameterMarkerStrategy;
|
||||
import org.hibernate.testing.orm.junit.Setting;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
import org.hibernate.testing.jdbc.SQLStatementInspector;
|
||||
|
@ -45,8 +42,8 @@ import static org.hibernate.internal.util.StringHelper.*;
|
|||
*/
|
||||
@ServiceRegistry( services = @ServiceRegistry.Service(
|
||||
role = ParameterMarkerStrategy.class,
|
||||
impl = ParameterMarkerStrategyTests.ParameterMarkerStrategyImpl.class
|
||||
), settings = @Setting(name = AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY, value = "true") )
|
||||
impl = ParameterMarkerStrategyTests.ParameterMarkerStrategyImpl.class )
|
||||
)
|
||||
@DomainModel( annotatedClasses = {
|
||||
EntityOfBasics.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
|
||||
@FailureExpected
|
||||
@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]]
|
||||
== 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
|
||||
** Removed `hibernate.mapping.precedence` and friends
|
||||
** Removed `hibernate.allow_refresh_detached_entity`
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue