diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 2546bc304f..bc39445891 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -141,10 +141,10 @@ import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.NaturalIdMapping; import org.hibernate.metamodel.mapping.Queryable; import org.hibernate.metamodel.mapping.StateArrayContributorMapping; +import org.hibernate.metamodel.mapping.StateArrayContributorMetadata; import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType; import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper; import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess; -import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.spi.EntityRepresentationStrategy; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; @@ -159,10 +159,7 @@ import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.Setter; import org.hibernate.query.ComparisonOperator; import org.hibernate.query.NavigablePath; -import org.hibernate.query.sqm.SqmPathSource; -import org.hibernate.query.sqm.sql.SqlAstCreationState; import org.hibernate.query.sqm.sql.SqlExpressionResolver; -import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.sql.Alias; import org.hibernate.sql.Delete; import org.hibernate.sql.Insert; @@ -174,7 +171,6 @@ import org.hibernate.sql.SimpleSelect; import org.hibernate.sql.Template; import org.hibernate.sql.Update; import org.hibernate.sql.ast.Clause; -import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.spi.SqlAliasBase; import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator; import org.hibernate.sql.ast.spi.SqlAliasStemHelper; @@ -5357,7 +5353,12 @@ public abstract class AbstractEntityPersister @Override public Object getVersion(Object object) { - return getVersionMapping().getAttributeMetadataAccess().resolveAttributeMetadata( this ).getPropertyAccess().getGetter().get( object ); + if ( getVersionMapping() == null ) { + return null; + } + final StateArrayContributorMetadata attrMetadata = getVersionMapping().getAttributeMetadataAccess().resolveAttributeMetadata( this ); + assert attrMetadata != null; + return attrMetadata.getPropertyAccess().getGetter().get( object ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/LoadingSmokeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/LoadingSmokeTests.java new file mode 100644 index 0000000000..5d8f612055 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/LoadingSmokeTests.java @@ -0,0 +1,87 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.loading; + +import org.hibernate.Hibernate; +import org.hibernate.boot.MetadataSources; +import org.hibernate.query.spi.QueryImplementor; + +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.testing.orm.domain.StandardDomainModel; +import org.hibernate.testing.orm.domain.gambit.BasicEntity; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.FailureExpected; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryFunctionalTesting; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import org.hamcrest.MatcherAssert; + +import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * @author Steve Ebersole + */ +@DomainModel( + standardModels = StandardDomainModel.GAMBIT +) +@SessionFactory +@SessionFactoryFunctionalTesting +@SuppressWarnings("WeakerAccess") +public class LoadingSmokeTests { + @Test + public void testBasicLoad(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + final BasicEntity loaded = session.byId( BasicEntity.class ).getReference( 1 ); + assertThat( loaded, notNullValue() ); + assertFalse( Hibernate.isInitialized( loaded ) ); + } + ); + } + + @Test + @FailureExpected( reason = "read-by-position not yet implemented for loading" ) + public void testBasicGet(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + final BasicEntity gotten = session.byId( BasicEntity.class ).load( 1 ); + assertThat( gotten, notNullValue() ); + assertTrue( Hibernate.isInitialized( gotten ) ); + } + ); + } + + @BeforeAll + public void createTestData(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + session.persist( new BasicEntity( 1, "first" ) ); + session.persist( new BasicEntity( 2, "second" ) ); + } + ); + } + + @AfterAll + public void deleteTestData(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + session.doWork( + connection -> { + connection.prepareStatement( "delete from BasicEntity" ).execute(); + } + ); + } + ); + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java index 1093c34442..ce197a7b8d 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java @@ -32,7 +32,7 @@ public class DomainModelExtension return JUnitHelper.locateExtensionStore( ServiceRegistryExtension.class, context, testInstance ); } - public static DomainModelScope findMetamodelScope(Object testInstance, ExtensionContext context) { + public static DomainModelScope findDomainModelScope(Object testInstance, ExtensionContext context) { final ExtensionContext.Store store = locateExtensionStore( testInstance, context ); final DomainModelScope existing = (DomainModelScope) store.get( MODEL_KEY ); if ( existing != null ) { @@ -120,7 +120,7 @@ public class DomainModelExtension @Override public void postProcessTestInstance(Object testInstance, ExtensionContext context) { - findMetamodelScope( testInstance, context ); + findDomainModelScope( testInstance, context ); } @Override diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelParameterResolver.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelParameterResolver.java index 248992f6f8..6393ec0ad9 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelParameterResolver.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelParameterResolver.java @@ -28,7 +28,7 @@ public class DomainModelParameterResolver implements ParameterResolver { public Object resolveParameter( ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { - final DomainModelScope modelScope = DomainModelExtension.findMetamodelScope( + final DomainModelScope modelScope = DomainModelExtension.findDomainModelScope( extensionContext.getRequiredTestInstance(), extensionContext ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactory.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactory.java index 9e73795f25..6f42025e75 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactory.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactory.java @@ -42,6 +42,7 @@ public @interface SessionFactory { String sessionFactoryName() default ""; boolean generateStatistics() default false; + boolean exportSchema() default true; Class interceptorClass() default Interceptor.class; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java index 56aa92d1a5..ec63deb34a 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java @@ -6,17 +6,26 @@ */ package org.hibernate.testing.orm.junit; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import java.util.function.Consumer; import java.util.function.Function; import org.hibernate.Interceptor; +import org.hibernate.SessionFactoryObserver; import org.hibernate.Transaction; import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.util.StringHelper; import org.hibernate.resource.jdbc.spi.StatementInspector; +import org.hibernate.tool.schema.Action; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator.ActionGrouping; import org.junit.jupiter.api.extension.AfterAllCallback; import org.junit.jupiter.api.extension.ExtensionContext; @@ -49,6 +58,8 @@ public class SessionFactoryExtension SessionFactoryProducer producer = null; + final DomainModelScope domainModelScope = DomainModelExtension.findDomainModelScope( testInstance, context ); + if ( testInstance instanceof SessionFactoryProducer ) { producer = (SessionFactoryProducer) testInstance; } @@ -85,7 +96,13 @@ public class SessionFactoryExtension ); } - return (SessionFactoryImplementor) sessionFactoryBuilder.build(); + final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) sessionFactoryBuilder.build(); + + if ( sessionFactoryConfig.exportSchema() ) { + prepareSchemaExport( sessionFactory, model ); + } + + return sessionFactory; } catch (Exception e) { throw new RuntimeException( "Could not build SessionFactory", e ); @@ -98,9 +115,8 @@ public class SessionFactoryExtension throw new IllegalStateException( "Could not determine SessionFactory producer" ); } - final SessionFactoryScopeImpl sfScope = new SessionFactoryScopeImpl( - DomainModelExtension.findMetamodelScope( testInstance, context ), + domainModelScope, producer ); @@ -113,6 +129,40 @@ public class SessionFactoryExtension return sfScope; } + private static void prepareSchemaExport( + SessionFactoryImplementor sessionFactory, + MetadataImplementor model) { + final Map baseProperties = sessionFactory.getProperties(); + + final ActionGrouping actions = ActionGrouping.interpret( baseProperties ); + + // if there are explicit setting for auto schema tooling then skip the annotation + if ( actions.getDatabaseAction() != Action.NONE || actions.getScriptAction() != Action.NONE ) { + // the properties contained explicit settings for auto schema tooling - skip the annotation + return; + } + + final HashMap settings = new HashMap<>( baseProperties ); + //noinspection unchecked + settings.put( AvailableSettings.HBM2DDL_DATABASE_ACTION, Action.CREATE_DROP ); + + final StandardServiceRegistry serviceRegistry = model.getMetadataBuildingOptions().getServiceRegistry(); + + SchemaManagementToolCoordinator.process( + model, + serviceRegistry, + settings, + action -> sessionFactory.addObserver( + new SessionFactoryObserver() { + @Override + public void sessionFactoryClosing(org.hibernate.SessionFactory factory) { + action.perform( serviceRegistry ); + } + } + ) + ); + } + @Override public void postProcessTestInstance(Object testInstance, ExtensionContext context) { log.tracef( "#postProcessTestInstance(%s, %s)", testInstance, context.getDisplayName() );