HHH-16180 - Add test and fix (AssertionError when using using native query on table with InheritanceStrategy.JOINED)
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
This commit is contained in:
parent
c67dbc0013
commit
2b4201e413
|
@ -119,60 +119,7 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
|
|||
}
|
||||
|
||||
private Expression createCaseSearchedExpression(TableGroup entityTableGroup) {
|
||||
return new SelfRenderingExpression() {
|
||||
CaseSearchedExpression caseSearchedExpression;
|
||||
|
||||
@Override
|
||||
public void renderToSql(
|
||||
SqlAppender sqlAppender,
|
||||
SqlAstTranslator<?> walker,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
if ( caseSearchedExpression == null ) {
|
||||
// todo (6.0): possible optimization is to omit cases for table reference joins, that touch a super class, where a subclass is inner joined due to pruning
|
||||
caseSearchedExpression = new CaseSearchedExpression( CaseStatementDiscriminatorMappingImpl.this );
|
||||
tableDiscriminatorDetailsMap.forEach(
|
||||
(tableName, tableDiscriminatorDetails) -> {
|
||||
final TableReference tableReference = entityTableGroup.getTableReference(
|
||||
entityTableGroup.getNavigablePath(),
|
||||
tableName,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
if ( tableReference == null ) {
|
||||
// assume this is because it is a table that is not part of the processing entity's sub-hierarchy
|
||||
return;
|
||||
}
|
||||
|
||||
final Predicate predicate = new NullnessPredicate(
|
||||
new ColumnReference(
|
||||
tableReference,
|
||||
tableDiscriminatorDetails.getCheckColumnName(),
|
||||
false,
|
||||
null,
|
||||
getJdbcMapping()
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
caseSearchedExpression.when(
|
||||
predicate,
|
||||
new QueryLiteral<>(
|
||||
tableDiscriminatorDetails.getDiscriminatorValue(),
|
||||
getUnderlyingJdbcMappingType()
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
caseSearchedExpression.accept( walker );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMappingContainer getExpressionType() {
|
||||
return CaseStatementDiscriminatorMappingImpl.this;
|
||||
}
|
||||
};
|
||||
return new CaseStatementDiscriminatorExpression( entityTableGroup );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -281,4 +228,63 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
|
|||
}
|
||||
}
|
||||
|
||||
public final class CaseStatementDiscriminatorExpression implements SelfRenderingExpression {
|
||||
private final TableGroup entityTableGroup;
|
||||
CaseSearchedExpression caseSearchedExpression;
|
||||
|
||||
public CaseStatementDiscriminatorExpression(TableGroup entityTableGroup) {
|
||||
this.entityTableGroup = entityTableGroup;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderToSql(
|
||||
SqlAppender sqlAppender,
|
||||
SqlAstTranslator<?> walker,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
if ( caseSearchedExpression == null ) {
|
||||
// todo (6.0): possible optimization is to omit cases for table reference joins, that touch a super class, where a subclass is inner joined due to pruning
|
||||
caseSearchedExpression = new CaseSearchedExpression( CaseStatementDiscriminatorMappingImpl.this );
|
||||
tableDiscriminatorDetailsMap.forEach(
|
||||
(tableName, tableDiscriminatorDetails) -> {
|
||||
final TableReference tableReference = entityTableGroup.getTableReference(
|
||||
entityTableGroup.getNavigablePath(),
|
||||
tableName,
|
||||
false,
|
||||
false
|
||||
);
|
||||
|
||||
if ( tableReference == null ) {
|
||||
// assume this is because it is a table that is not part of the processing entity's sub-hierarchy
|
||||
return;
|
||||
}
|
||||
|
||||
final Predicate predicate = new NullnessPredicate(
|
||||
new ColumnReference(
|
||||
tableReference,
|
||||
tableDiscriminatorDetails.getCheckColumnName(),
|
||||
false,
|
||||
null,
|
||||
getJdbcMapping()
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
caseSearchedExpression.when(
|
||||
predicate,
|
||||
new QueryLiteral<>(
|
||||
tableDiscriminatorDetails.getDiscriminatorValue(),
|
||||
getUnderlyingJdbcMappingType()
|
||||
)
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
caseSearchedExpression.accept( walker );
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMappingContainer getExpressionType() {
|
||||
return CaseStatementDiscriminatorMappingImpl.this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,6 +28,7 @@ import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
|||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.CaseStatementDiscriminatorMappingImpl;
|
||||
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.spi.EntityIdentifierNavigablePath;
|
||||
|
@ -65,6 +66,7 @@ import static org.hibernate.query.results.ResultsHelper.attributeName;
|
|||
public class DomainResultCreationStateImpl
|
||||
implements DomainResultCreationState, SqlAstCreationState, SqlAstProcessingState, SqlExpressionResolver {
|
||||
|
||||
private static final String DISCRIMINATOR_ALIAS = "clazz_";
|
||||
private final String stateIdentifier;
|
||||
private final FromClauseAccessImpl fromClauseAccess;
|
||||
|
||||
|
@ -295,6 +297,26 @@ public class DomainResultCreationStateImpl
|
|||
|
||||
return sqlSelection;
|
||||
}
|
||||
else if ( created instanceof CaseStatementDiscriminatorMappingImpl.CaseStatementDiscriminatorExpression ) {
|
||||
final int valuesArrayPosition;
|
||||
if ( nestingFetchParent != null ) {
|
||||
valuesArrayPosition = nestingFetchParent.getReferencedMappingType().getSelectableIndex( DISCRIMINATOR_ALIAS );
|
||||
}
|
||||
else {
|
||||
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( DISCRIMINATOR_ALIAS );
|
||||
valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
|
||||
}
|
||||
|
||||
final ResultSetMappingSqlSelection sqlSelection = new ResultSetMappingSqlSelection(
|
||||
valuesArrayPosition,
|
||||
created.getExpressionType().getSingleJdbcMapping()
|
||||
);
|
||||
|
||||
sqlSelectionMap.put( key, sqlSelection );
|
||||
sqlSelectionConsumer.accept( sqlSelection );
|
||||
|
||||
return sqlSelection;
|
||||
}
|
||||
|
||||
return created;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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.hql.joinedSubclass;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
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.AfterAll;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import jakarta.persistence.Basic;
|
||||
import jakarta.persistence.Entity;
|
||||
import jakarta.persistence.GeneratedValue;
|
||||
import jakarta.persistence.Id;
|
||||
import jakarta.persistence.Inheritance;
|
||||
import jakarta.persistence.InheritanceType;
|
||||
|
||||
/**
|
||||
* @author Jan Schatteman
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
JoinedSubclassNativeQueryTest.Person.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
public class JoinedSubclassNativeQueryTest {
|
||||
|
||||
@BeforeAll
|
||||
public void setup(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Person p = new Person();
|
||||
p.setFirstName( "Jan" );
|
||||
session.persist( p );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> session.createMutationQuery( "delete from Person" ).executeUpdate()
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue( jiraKey = "HHH-16180")
|
||||
public void testJoinedInheritanceNativeQuery(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Person p = session.createNativeQuery( "select p.*, 0 as clazz_ from Person p", Person.class ).getSingleResult();
|
||||
Assertions.assertNotNull( p );
|
||||
Assertions.assertEquals( p.getFirstName(), "Jan" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public static class Person {
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Basic(optional = false)
|
||||
private String firstName;
|
||||
|
||||
public String getFirstName() {
|
||||
return firstName;
|
||||
}
|
||||
|
||||
public void setFirstName(String firstName) {
|
||||
this.firstName = firstName;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue