work on aggregate composite identifier

This commit is contained in:
Andrea Boriero 2019-11-21 08:38:07 +00:00 committed by Steve Ebersole
parent 04c5160e02
commit 9a0ad0f21d
9 changed files with 716 additions and 46 deletions

View File

@ -277,6 +277,7 @@ public class MetamodelSelectBuilderProcess {
final ColumnReference columnReference = columnReferences.get( j ); final ColumnReference columnReference = columnReferences.get( j );
final JdbcParameter jdbcParameter = new JdbcParameterImpl( columnReference.getJdbcMapping() ); final JdbcParameter jdbcParameter = new JdbcParameterImpl( columnReference.getJdbcMapping() );
jdbcParameterConsumer.accept( jdbcParameter ); jdbcParameterConsumer.accept( jdbcParameter );
tupleParams.add( jdbcParameter );
} }
final SqlTuple paramTuple = new SqlTuple( tupleParams, keyPart ); final SqlTuple paramTuple = new SqlTuple( tupleParams, keyPart );
predicate.addExpression( paramTuple ); predicate.addExpression( paramTuple );

View File

@ -279,7 +279,16 @@ public class EmbeddableMappingType implements ManagedMappingType {
JdbcValuesConsumer consumer, JdbcValuesConsumer consumer,
SharedSessionContractImplementor session) { SharedSessionContractImplementor session) {
attributeMappings.forEach( attributeMappings.forEach(
(s, attributeMapping) -> attributeMapping.visitJdbcValues( value, clause, consumer, session ) (s, attributeMapping) -> {
Object o = attributeMapping.getPropertyAccess().getGetter().get( value );
attributeMapping.visitJdbcValues( o, clause, consumer, session );
}
);
}
public void visitColumns(ColumnConsumer consumer) {
attributeMappings.values().forEach(
attributeMapping -> attributeMapping.visitColumns( consumer )
); );
} }

View File

@ -0,0 +1,16 @@
/*
* 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.metamodel.mapping;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
/**
* @author Andrea Boriero
*/
public interface EmbeddedIdentifierMapping extends EntityIdentifierMapping, EmbeddableValuedModelPart {
}

View File

@ -0,0 +1,284 @@
/*
* 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.metamodel.mapping.internal;
import java.util.Arrays;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.mapping.ColumnConsumer;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddedIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.JoinType;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.CompositeTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupProducer;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
import org.hibernate.sql.results.internal.domain.composite.CompositeFetch;
import org.hibernate.sql.results.internal.domain.composite.CompositeResult;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Andrea Boriero
*/
public class EmbeddedIdentifierMappingImpl extends AbstractStateArrayContributorMapping
implements EmbeddedIdentifierMapping {
private final PropertyAccess propertyAccess;
private final String tableExpression;
private final String[] attrColumnNames;
public EmbeddedIdentifierMappingImpl(
String name,
MappingType type,
StateArrayContributorMetadataAccess attributeMetadataAccess,
FetchStrategy mappedFetchStrategy,
int stateArrayPosition,
ManagedMappingType declaringType,
PropertyAccess propertyAccess,
String tableExpression,
String[] attrColumnNames) {
super( name, type, attributeMetadataAccess, mappedFetchStrategy, stateArrayPosition, declaringType );
this.propertyAccess = propertyAccess;
this.tableExpression = tableExpression;
this.attrColumnNames = attrColumnNames;
}
@Override
public String getPartName() {
return getAttributeName();
}
@Override
public PropertyAccess getPropertyAccess() {
return propertyAccess;
}
@Override
public EmbeddableMappingType getEmbeddableTypeDescriptor() {
return getMappedTypeDescriptor();
}
@Override
public EmbeddableMappingType getMappedTypeDescriptor() {
return (EmbeddableMappingType) super.getMappedTypeDescriptor();
}
@Override
public String getContainingTableExpression() {
return tableExpression;
}
@Override
public List<String> getMappedColumnExpressions() {
return Arrays.asList( attrColumnNames );
}
@Override
public SingularAttributeMapping getParentInjectionAttributeMapping() {
return null;
}
@Override
public void visitJdbcTypes(
Consumer<JdbcMapping> action,
Clause clause,
TypeConfiguration typeConfiguration) {
getMappedTypeDescriptor().visitJdbcTypes( action,clause,typeConfiguration );
}
@Override
public void visitJdbcValues(
Object value, Clause clause, JdbcValuesConsumer valuesConsumer, SharedSessionContractImplementor session) {
getEmbeddableTypeDescriptor().visitJdbcValues( value, clause, valuesConsumer, session );
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
return new CompositeResult<>(
navigablePath,
this,
resultVariable,
creationState
);
}
@Override
public Expression toSqlExpression(
TableGroup tableGroup,
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
final List<ColumnReference> columnReferences = CollectionHelper.arrayList( attrColumnNames.length );
final TableReference tableReference = tableGroup.resolveTableReference( getContainingTableExpression() );
getEmbeddableTypeDescriptor().visitJdbcTypes(
new Consumer<JdbcMapping>() {
private int index = 0;
@Override
public void accept(JdbcMapping jdbcMapping) {
final String attrColumnExpr = attrColumnNames[ index++ ];
final Expression columnReference = sqlAstCreationState.getSqlExpressionResolver().resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
tableReference,
attrColumnExpr
),
sqlAstProcessingState -> new ColumnReference(
tableReference.getIdentificationVariable(),
attrColumnExpr,
jdbcMapping,
sqlAstCreationState.getCreationContext().getSessionFactory()
)
);
columnReferences.add( (ColumnReference) columnReference );
}
},
clause,
sqlAstCreationState.getCreationContext().getSessionFactory().getTypeConfiguration()
);
return new SqlTuple( columnReferences, this );
}
@Override
public TableGroupJoin createTableGroupJoin(
NavigablePath navigablePath,
TableGroup lhs,
String explicitSourceAlias,
JoinType joinType,
LockMode lockMode,
SqlAliasBaseGenerator aliasBaseGenerator,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
final CompositeTableGroup compositeTableGroup = new CompositeTableGroup(
navigablePath,
this,
lhs
);
lhs.addTableGroupJoin( new TableGroupJoin( navigablePath, JoinType.INNER, compositeTableGroup, null ) );
return new TableGroupJoin(
navigablePath,
joinType,
compositeTableGroup
);
}
@Override
public String getSqlAliasStem() {
return getAttributeName();
}
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
return getMappedTypeDescriptor().findSubPart( name, treatTargetType );
}
@Override
public void visitSubParts(
Consumer<ModelPart> consumer, EntityMappingType treatTargetType) {
getMappedTypeDescriptor().visitSubParts( consumer, treatTargetType );
}
@Override
public void applyTableReferences(
SqlAliasBase sqlAliasBase,
JoinType baseJoinType,
TableReferenceCollector collector,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
getEmbeddableTypeDescriptor().visitAttributeMappings(
attrMapping -> {
if ( attrMapping instanceof TableGroupProducer ) {
( (TableGroupProducer) attrMapping ).applyTableReferences(
sqlAliasBase,
baseJoinType,
collector,
sqlExpressionResolver,
creationContext
);
}
else if ( attrMapping.getMappedTypeDescriptor() instanceof TableGroupProducer ) {
( (TableGroupProducer) attrMapping.getMappedTypeDescriptor() ).applyTableReferences(
sqlAliasBase,
baseJoinType,
collector,
sqlExpressionResolver,
creationContext
);
}
}
);
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
return new CompositeFetch(
fetchablePath,
this,
fetchParent,
fetchTiming,
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
creationState
);
}
@Override
public int getNumberOfFetchables() {
return getEmbeddableTypeDescriptor().getNumberOfAttributeMappings();
}
public void visitColumns(ColumnConsumer consumer) {
getEmbeddableTypeDescriptor().visitColumns( consumer );
}
}

View File

@ -283,6 +283,8 @@ public class MappingModelCreationHelper {
public static EntityIdentifierMapping buildEncapsulatedCompositeIdentifierMapping( public static EntityIdentifierMapping buildEncapsulatedCompositeIdentifierMapping(
EntityPersister entityPersister, EntityPersister entityPersister,
Property bootProperty,
String attributeName,
String rootTableName, String rootTableName,
String[] rootTableKeyColumnNames, String[] rootTableKeyColumnNames,
CompositeType cidType, CompositeType cidType,
@ -294,48 +296,29 @@ public class MappingModelCreationHelper {
final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy() final PropertyAccess propertyAccess = entityPersister.getRepresentationStrategy()
.resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() ); .resolvePropertyAccess( bootEntityDescriptor.getIdentifierProperty() );
return new EntityIdentifierMapping() { final StateArrayContributorMetadataAccess attributeMetadataAccess = getStateArrayContributorMetadataAccess(
@Override propertyAccess
public PropertyAccess getPropertyAccess() { );
return propertyAccess;
}
@Override final EmbeddableMappingType embeddableMappingType = EmbeddableMappingType.from(
public MappingType getMappedTypeDescriptor() { (Component) bootProperty.getValue(),
return ( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getMappedTypeDescriptor(); cidType,
} attributeMappingType -> new EmbeddedIdentifierMappingImpl(
attributeName,
attributeMappingType,
attributeMetadataAccess,
FetchStrategy.IMMEDIATE_JOIN,
0,
entityPersister,
propertyAccess,
rootTableName,
rootTableKeyColumnNames
),
creationProcess
);
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override return (EmbeddedIdentifierMappingImpl) embeddableMappingType.getEmbeddedValueMapping();
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
return ( (ModelPart) entityPersister.getIdentifierType() ).createDomainResult(
navigablePath,
tableGroup,
resultVariable,
creationState
);
}
@Override
public void applySqlSelections(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
( (ModelPart) entityPersister.getIdentifierType() ).applySqlSelections(
navigablePath,
tableGroup,
creationState
);
}
};
} }
public static EntityIdentifierMapping buildNonEncapsulatedCompositeIdentifierMapping( public static EntityIdentifierMapping buildNonEncapsulatedCompositeIdentifierMapping(
@ -639,6 +622,58 @@ public class MappingModelCreationHelper {
}; };
} }
protected static StateArrayContributorMetadataAccess getStateArrayContributorMetadataAccess(
PropertyAccess propertyAccess) {
return entityMappingType -> new StateArrayContributorMetadata() {
private final MutabilityPlan mutabilityPlan = ImmutableMutabilityPlan.INSTANCE;
@Override
public PropertyAccess getPropertyAccess() {
return propertyAccess;
}
@Override
public MutabilityPlan getMutabilityPlan() {
return mutabilityPlan;
}
@Override
public boolean isNullable() {
return false;
}
@Override
public boolean isInsertable() {
return true;
}
@Override
public boolean isUpdatable() {
return false;
}
@Override
public boolean isIncludedInDirtyChecking() {
return false;
}
@Override
public boolean isIncludedInOptimisticLocking() {
// todo (6.0) : do not sure this is correct
return true;
}
@Override
public CascadeStyle getCascadeStyle() {
// todo (6.0) : do not sure this is correct
return null;
}
};
}
public static PluralAttributeMapping buildPluralAttributeMapping( public static PluralAttributeMapping buildPluralAttributeMapping(
String attrName, String attrName,
int stateArrayPosition, int stateArrayPosition,

View File

@ -6121,6 +6121,12 @@ public abstract class AbstractEntityPersister
return; return;
} }
final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext();
final PersistentClass bootEntityDescriptor = creationContext
.getBootModel()
.getEntityBinding( getEntityName() );
if ( superMappingType != null && shouldProcessSuperMapping() ) { if ( superMappingType != null && shouldProcessSuperMapping() ) {
( (InFlightEntityMappingType) superMappingType ).prepareMappingModel( creationProcess ); ( (InFlightEntityMappingType) superMappingType ).prepareMappingModel( creationProcess );
@ -6131,7 +6137,8 @@ public abstract class AbstractEntityPersister
else { else {
identifierMapping = creationProcess.processSubPart( identifierMapping = creationProcess.processSubPart(
EntityIdentifierMapping.ROLE_LOCAL_NAME, EntityIdentifierMapping.ROLE_LOCAL_NAME,
(role, creationProcess1) -> generateIdentifierMapping( creationProcess ) (role, creationProcess1) ->
generateIdentifierMapping( creationProcess, bootEntityDescriptor.getIdentifierProperty() )
); );
if ( getVersionType() == null ) { if ( getVersionType() == null ) {
@ -6153,11 +6160,7 @@ public abstract class AbstractEntityPersister
naturalIdMapping = null; naturalIdMapping = null;
} }
final RuntimeModelCreationContext creationContext = creationProcess.getCreationContext();
final PersistentClass bootEntityDescriptor = creationContext
.getBootModel()
.getEntityBinding( getEntityName() );
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel(); final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
int stateArrayPosition = getStateArrayInitialPosition( creationProcess ); int stateArrayPosition = getStateArrayInitialPosition( creationProcess );
@ -6362,7 +6365,7 @@ public abstract class AbstractEntityPersister
} }
private EntityIdentifierMapping generateIdentifierMapping(MappingModelCreationProcess creationProcess) { private EntityIdentifierMapping generateIdentifierMapping(MappingModelCreationProcess creationProcess, Property identifierProperty) {
final Type idType = getIdentifierType(); final Type idType = getIdentifierType();
if ( idType instanceof CompositeType ) { if ( idType instanceof CompositeType ) {
@ -6370,6 +6373,8 @@ public abstract class AbstractEntityPersister
if ( ! cidType.isEmbedded() ) { if ( ! cidType.isEmbedded() ) {
return MappingModelCreationHelper.buildEncapsulatedCompositeIdentifierMapping( return MappingModelCreationHelper.buildEncapsulatedCompositeIdentifierMapping(
this, this,
identifierProperty,
identifierProperty.getName(),
getRootTableName(), getRootTableName(),
rootTableKeyColumnNames, rootTableKeyColumnNames,
cidType, cidType,

View File

@ -0,0 +1,123 @@
/*
* 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.sql.exec;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.orm.domain.gambit.EmbeddedIdEntity;
import org.hibernate.testing.orm.domain.gambit.EmbeddedIdEntity.EmbeddedIdEntityId;
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.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNull.notNullValue;
/**
* @author Chris Cranford
*/
@DomainModel(
annotatedClasses = {
EmbeddedIdEntity.class
}
)
@ServiceRegistry
@SessionFactory(generateStatistics = true)
public class EmbeddedIdEntityTest {
private EmbeddedIdEntityId entityId;
@BeforeEach
public void setUp(SessionFactoryScope scope) {
final EmbeddedIdEntity entity = new EmbeddedIdEntity();
entityId = new EmbeddedIdEntityId( 25, "Acme" );
scope.inTransaction(
session -> {
entity.setId( entityId );
entity.setData( "test" );
session.save( entity );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
sesison ->
sesison.createQuery( "delete from EmbeddedIdEntity" ).executeUpdate()
);
}
@Test
public void testHqlSelectAField(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final String value = session.createQuery( "select e.data FROM EmbeddedIdEntity e", String.class )
.uniqueResult();
assertThat( value, is( "test" ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
@Test
public void testHqlSelect(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final EmbeddedIdEntity loaded = session.createQuery(
"select e FROM EmbeddedIdEntity e",
EmbeddedIdEntity.class
).uniqueResult();
assertThat( loaded.getData(), is( "test" ) );
assertThat( loaded.getId(), equalTo( entityId ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
@Test
public void testHqlSelectOnlyTheEmbeddedId(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final EmbeddedIdEntityId value = session.createQuery(
"select e.id FROM EmbeddedIdEntity e",
EmbeddedIdEntityId.class
).uniqueResult();
assertThat( value, equalTo( entityId ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
@Test
public void testGet(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final EmbeddedIdEntity loaded = session.get( EmbeddedIdEntity.class, entityId );
assertThat( loaded, notNullValue() );
assertThat( loaded.getId(), notNullValue() );
assertThat( loaded.getId(), equalTo( entityId ) );
assertThat( loaded.getData(), is( "test" ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
}

View File

@ -0,0 +1,123 @@
/*
* 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.sql.exec;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.testing.orm.domain.gambit.EntityWithNotAggregateId;
import org.hibernate.testing.orm.domain.gambit.EntityWithNotAggregateId.PK;
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.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNull.notNullValue;
@DomainModel(
annotatedClasses = {
EntityWithNotAggregateId.class
}
)
@ServiceRegistry
@SessionFactory(generateStatistics = true)
@Disabled(value = "non aggregate composit id has not been yet implemented")
public class EntityWithNotAggregateIdTest {
private PK entityId;
@BeforeEach
public void setUp(SessionFactoryScope scope) {
final EntityWithNotAggregateId entity = new EntityWithNotAggregateId();
entityId = new PK( 25, "Acme" );
scope.inTransaction(
session -> {
entity.setId( entityId );
entity.setData( "test" );
session.save( entity );
}
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
sesison ->
sesison.createQuery( "delete from EntityWithIdClass" ).executeUpdate()
);
}
@Test
public void testHqlSelectAField(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final String value = session.createQuery( "select e.data FROM EntityWithIdClass e", String.class )
.uniqueResult();
assertThat( value, is( "test" ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
@Test
public void testHqlSelect(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final EntityWithNotAggregateId loaded = session.createQuery(
"select e FROM EntityWithIdClass e",
EntityWithNotAggregateId.class
).uniqueResult();
assertThat( loaded.getData(), is( "test" ) );
assertThat( loaded.getId(), equalTo( entityId ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
@Test
public void testHqlSelectOnlyTheEmbeddedId(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final EntityWithNotAggregateId value = session.createQuery(
"select e.id FROM EntityWithIdClass e",
EntityWithNotAggregateId.class
).uniqueResult();
assertThat( value, equalTo( entityId ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
@Test
public void testGet(SessionFactoryScope scope) {
StatisticsImplementor statistics = scope.getSessionFactory().getStatistics();
statistics.clear();
scope.inTransaction(
session -> {
final EntityWithNotAggregateId loaded = session.get( EntityWithNotAggregateId.class, entityId );
assertThat( loaded, notNullValue() );
assertThat( loaded.getId(), notNullValue() );
assertThat( loaded.getId(), equalTo( entityId ) );
assertThat( loaded.getData(), is( "test" ) );
}
);
assertThat( statistics.getPrepareStatementCount(), is( 1L ) );
}
}

View File

@ -0,0 +1,74 @@
/*
* 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.testing.orm.domain.gambit;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
/**
* @author Andrea Boriero
*/
@Entity
@IdClass(EntityWithNotAggregateId.PK.class)
public class EntityWithNotAggregateId {
@Id
private Integer value1;
@Id
private String value2;
private String data;
public PK getId() {
return new PK( value1, value2 );
}
public void setId(PK id) {
this.value1 = id.getValue1();
this.value2 = id.getValue2();
}
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public static class PK implements Serializable {
private Integer value1;
private String value2;
public PK() {
}
public PK(Integer value1, String value2) {
this.value1 = value1;
this.value2 = value2;
}
public Integer getValue1() {
return value1;
}
public void setValue1(Integer value1) {
this.value1 = value1;
}
public String getValue2() {
return value2;
}
public void setValue2(String value2) {
this.value2 = value2;
}
}
}