discriminator work

- Handle discriminator as Fetch for entity ResultGraphNodes.  This allows us to make the distinction about whether to handle the discriminator as `Class` or as its "underlying" type when selecting it.  Fetches return the underlying type.  DomainResults return `Class`, or String for entity-named entity mappings
This commit is contained in:
Steve Ebersole 2021-08-20 14:26:40 -05:00
parent fb651ef07d
commit 524b2982cf
4 changed files with 99 additions and 29 deletions

View File

@ -36,37 +36,20 @@ public class EntityResultImpl implements EntityResult {
private final NavigablePath navigablePath;
private final EntityValuedModelPart entityValuedModelPart;
private final DomainResult identifierResult;
private final Fetch discriminatorFetch;
private final DomainResult<?> identifierResult;
private final BasicFetch<?> discriminatorFetch;
private final List<Fetch> fetches;
private final String resultAlias;
private final LockMode lockMode;
public EntityResultImpl(
NavigablePath navigablePath,
EntityValuedModelPart entityValuedModelPart,
String resultAlias,
LockMode lockMode,
BasicFetch<?> discriminatorFetch,
DomainResultCreationState creationState) {
this(
navigablePath,
entityValuedModelPart,
resultAlias,
lockMode,
entityResult -> discriminatorFetch,
creationState
);
}
@SuppressWarnings( { "PointlessNullCheck" } )
public EntityResultImpl(
NavigablePath navigablePath,
EntityValuedModelPart entityValuedModelPart,
String resultAlias,
LockMode lockMode,
Function<EntityResultImpl, BasicFetch> discriminatorFetchBuilder,
Function<EntityResultImpl, BasicFetch<?>> discriminatorFetchBuilder,
DomainResultCreationState creationState) {
this.navigablePath = navigablePath;
this.entityValuedModelPart = entityValuedModelPart;
@ -151,7 +134,7 @@ public class EntityResultImpl implements EntityResult {
}
@Override
public DomainResultAssembler createResultAssembler(AssemblerCreationState creationState) {
public DomainResultAssembler<?> createResultAssembler(AssemblerCreationState creationState) {
final EntityInitializer initializer = (EntityInitializer) creationState.resolveInitializer(
getNavigablePath(),
getReferencedModePart(),

View File

@ -24,7 +24,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.AbstractFetchParent;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import static org.hibernate.query.results.ResultsHelper.attributeName;
@ -36,9 +36,9 @@ import static org.hibernate.query.results.ResultsHelper.attributeName;
*/
public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent implements EntityResultGraphNode {
private final EntityValuedModelPart referencedModelPart;
private final DomainResult identifierResult;
private final Fetch discriminatorFetch;
private final DomainResult versionResult;
private final DomainResult<?> identifierResult;
private final BasicFetch<?> discriminatorFetch;
private final DomainResult<?> versionResult;
private final DomainResult<Object> rowIdResult;
private final EntityMappingType targetType;
@ -208,7 +208,7 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
return identifierResult;
}
public Fetch getDiscriminatorFetch() {
public BasicFetch<?> getDiscriminatorFetch() {
return discriminatorFetch;
}

View File

@ -10,7 +10,7 @@ import org.hibernate.LockMode;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.entity.AbstractEntityInitializer;
import org.hibernate.sql.results.graph.entity.EntityResultGraphNode;
@ -27,7 +27,7 @@ public class EntityResultInitializer extends AbstractEntityInitializer {
NavigablePath navigablePath,
LockMode lockMode,
DomainResult identifierResult,
Fetch discriminatorResult,
BasicFetch<?> discriminatorFetch,
DomainResult versionResult,
DomainResult<Object> rowIdResult,
AssemblerCreationState creationState) {
@ -36,7 +36,7 @@ public class EntityResultInitializer extends AbstractEntityInitializer {
navigablePath,
lockMode,
identifierResult,
discriminatorResult,
discriminatorFetch,
versionResult,
rowIdResult,
creationState

View File

@ -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.discriminator.joined;
import javax.persistence.Tuple;
import org.hibernate.testing.orm.junit.DomainModel;
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 org.assertj.core.api.Assertions;
/**
* @author Steve Ebersole
*/
@DomainModel(
xmlMappings = "org/hibernate/orm/test/discriminator/joined/JoinedSubclassInheritance.hbm.xml"
)
@SessionFactory
public class DiscriminatorQueryUsageTests {
@Test
public void testUsageAsSelection(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
final Tuple resultTuple = session
.createQuery( "select p.id as id, type(p) as type from ParentEntity p", Tuple.class )
.uniqueResult();
Assertions.assertThat( resultTuple.get( "id" ) ).isEqualTo( 1 );
Assertions.assertThat( resultTuple.get( "type" ) ).isEqualTo( ChildEntity.class );
} );
}
@Test
public void testUsageAsPredicate(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
final Integer id = session.createQuery( "select p.id from ParentEntity p where type(p) = ChildEntity", Integer.class ).uniqueResult();
Assertions.assertThat( id ).isEqualTo( 1 );
} );
}
@Test
public void testUsageAsPredicateOfUnderlyingType(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
final Integer id = session.createQuery( "select p.id from ParentEntity p where type(p) = 'ce'", Integer.class ).uniqueResult();
Assertions.assertThat( id ).isEqualTo( 1 );
} );
}
@Test
public void testUsageAsPredicateWithParam(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
final Integer id = session.createQuery( "select p.id from ParentEntity p where type(p) = :type", Integer.class )
.setParameter( "type", ChildEntity.class )
.uniqueResult();
Assertions.assertThat( id ).isEqualTo( 1 );
} );
}
@Test
public void testUsageAsPredicateWithParamOfUnderlyingType(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
final Integer id = session.createQuery( "select p.id from ParentEntity p where type(p) = :type", Integer.class )
.setParameter( "type", "ce" )
.uniqueResult();
Assertions.assertThat( id ).isEqualTo( 1 );
} );
}
@BeforeEach
public void createTestData(SessionFactoryScope scope) {
scope.inTransaction( (session) -> session.save( new ChildEntity( 1, "Child" ) ) );
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
session.createQuery( "delete from ParentEntity" ).executeUpdate();
} );
}
}