Fix issue with join subclass and JoinTable resolution
This commit is contained in:
parent
310abfcd95
commit
61e141cabf
|
@ -49,6 +49,7 @@ import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
|
|||
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityFetchSelectImpl;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityResultJoinedSubclassImpl;
|
||||
import org.hibernate.sql.results.internal.domain.CircularFetchImpl;
|
||||
import org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl;
|
||||
import org.hibernate.type.ForeignKeyDirection;
|
||||
|
@ -167,8 +168,8 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
|
|||
}
|
||||
|
||||
in such case the mappedBy is "primaryKey.card"
|
||||
the the navigable path is NavigablePath(Card.fields.{element}.{id}.card) and it does not contain the "primaryKey" part
|
||||
so in ored to recognize the bidirectionality the "primaryKey." is removed from the otherSidePropertyName value.
|
||||
the navigable path is NavigablePath(Card.fields.{element}.{id}.card) and it does not contain the "primaryKey" part,
|
||||
so in order to recognize the bidirectionality the "primaryKey." is removed from the otherSidePropertyName value.
|
||||
*/
|
||||
// todo (6.0): find a better solution for the embeddable part name not in the NavigablePath
|
||||
bidirectionalAttributeName = StringHelper.subStringNullIfEmpty(
|
||||
|
@ -399,30 +400,23 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
|
|||
);
|
||||
|
||||
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
|
||||
fromClauseAccess.resolveTableGroup(
|
||||
fetchablePath,
|
||||
np -> {
|
||||
final SqlAstJoinType sqlAstJoinType;
|
||||
if ( isNullable ) {
|
||||
sqlAstJoinType = SqlAstJoinType.LEFT;
|
||||
}
|
||||
else {
|
||||
sqlAstJoinType = SqlAstJoinType.INNER;
|
||||
}
|
||||
|
||||
|
||||
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
null,
|
||||
sqlAstJoinType,
|
||||
lockMode,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
}
|
||||
);
|
||||
if ( fetchParent instanceof EntityResultJoinedSubclassImpl &&
|
||||
( (EntityPersister) fetchParent.getReferencedModePart() ).findDeclaredAttributeMapping( getPartName() ) == null ) {
|
||||
final TableGroup tableGroupJoin = createTableGroupJoin(
|
||||
fetchablePath,
|
||||
lockMode,
|
||||
creationState,
|
||||
parentTableGroup
|
||||
);
|
||||
fromClauseAccess.registerTableGroup( fetchablePath, tableGroupJoin );
|
||||
}
|
||||
else {
|
||||
fromClauseAccess.resolveTableGroup(
|
||||
fetchablePath,
|
||||
np ->
|
||||
createTableGroupJoin( fetchablePath, lockMode, creationState, parentTableGroup )
|
||||
);
|
||||
}
|
||||
|
||||
creationState.registerVisitedAssociationKey( foreignKeyDescriptor.getAssociationKey() );
|
||||
return new EntityFetchJoinedImpl(
|
||||
|
@ -496,6 +490,30 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
|
|||
);
|
||||
}
|
||||
|
||||
private TableGroup createTableGroupJoin(
|
||||
NavigablePath fetchablePath,
|
||||
LockMode lockMode,
|
||||
DomainResultCreationState creationState, TableGroup parentTableGroup) {
|
||||
final SqlAstJoinType sqlAstJoinType;
|
||||
if ( isNullable ) {
|
||||
sqlAstJoinType = SqlAstJoinType.LEFT;
|
||||
}
|
||||
else {
|
||||
sqlAstJoinType = SqlAstJoinType.INNER;
|
||||
}
|
||||
|
||||
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||
fetchablePath,
|
||||
parentTableGroup,
|
||||
null,
|
||||
sqlAstJoinType,
|
||||
lockMode,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNumberOfFetchables() {
|
||||
return getEntityMappingType().getNumberOfFetchables();
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.orm.test.inheritance.discriminator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
|
||||
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.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* Test cases for joined inheritance with eager fetching.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
JoinedInheritanceEagerTest.BaseEntity.class,
|
||||
JoinedInheritanceEagerTest.EntityA.class,
|
||||
JoinedInheritanceEagerTest.EntityB.class,
|
||||
JoinedInheritanceEagerTest.EntityC.class,
|
||||
JoinedInheritanceEagerTest.EntityD.class
|
||||
}
|
||||
)
|
||||
@SessionFactory
|
||||
public class JoinedInheritanceEagerTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
EntityC entityC = new EntityC( 1L );
|
||||
EntityD entityD = new EntityD( 2L );
|
||||
|
||||
EntityB entityB = new EntityB( 3L );
|
||||
entityB.setRelation( entityD );
|
||||
|
||||
EntityA entityA = new EntityA( 4L );
|
||||
entityA.setRelation( entityC );
|
||||
|
||||
session.persist( entityC );
|
||||
session.persist( entityD );
|
||||
session.persist( entityA );
|
||||
session.persist( entityB );
|
||||
} );
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
EntityA entityA = session.get( EntityA.class, 4L );
|
||||
EntityB entityB = session.get( EntityB.class, 3L );
|
||||
EntityD entityD = session.get( EntityD.class, 2L );
|
||||
EntityC entityC = session.get( EntityC.class, 1L );
|
||||
|
||||
session.delete( entityD );
|
||||
session.delete( entityC );
|
||||
session.delete( entityA );
|
||||
session.delete( entityB );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12375")
|
||||
public void joinFindEntity(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
EntityA entityA = session.get( EntityA.class, 4L );
|
||||
assertTrue( Hibernate.isInitialized( entityA.getRelation() ) );
|
||||
assertFalse( Hibernate.isInitialized( entityA.getAttributes() ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12375")
|
||||
public void joinFindParenEntity(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
BaseEntity baseEntity = session.get( BaseEntity.class, 4L );
|
||||
assertThat( baseEntity, notNullValue() );
|
||||
assertThat( baseEntity, instanceOf( EntityA.class ) );
|
||||
assertTrue( Hibernate.isInitialized( ( (EntityA) baseEntity ).getRelation() ) );
|
||||
assertFalse( Hibernate.isInitialized( ( (EntityA) baseEntity ).getAttributes() ) );
|
||||
} );
|
||||
|
||||
scope.inTransaction( session -> {
|
||||
BaseEntity baseEntity = session.get( BaseEntity.class, 3L );
|
||||
assertThat( baseEntity, notNullValue() );
|
||||
assertThat( baseEntity, instanceOf( EntityB.class ) );
|
||||
assertTrue( Hibernate.isInitialized( ( (EntityB) baseEntity ).getRelation() ) );
|
||||
assertFalse( Hibernate.isInitialized( ( (EntityB) baseEntity ).getAttributes() ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12375")
|
||||
public void selectBaseType(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
List result = session.createQuery( "from BaseEntity" ).list();
|
||||
assertEquals( 2, result.size() );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "BaseEntity")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public static class BaseEntity {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public BaseEntity() {
|
||||
}
|
||||
|
||||
public BaseEntity(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "EntityA")
|
||||
public static class EntityA extends BaseEntity {
|
||||
@OneToMany(fetch = FetchType.LAZY)
|
||||
private Set<EntityC> attributes;
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
private EntityC relation;
|
||||
|
||||
public EntityA() {
|
||||
}
|
||||
|
||||
public EntityA(Long id) {
|
||||
super( id );
|
||||
}
|
||||
|
||||
public void setRelation(EntityC relation) {
|
||||
this.relation = relation;
|
||||
}
|
||||
|
||||
public EntityC getRelation() {
|
||||
return relation;
|
||||
}
|
||||
|
||||
public Set<EntityC> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "EntityB")
|
||||
public static class EntityB extends BaseEntity {
|
||||
@OneToMany(fetch = FetchType.LAZY)
|
||||
private Set<EntityD> attributes;
|
||||
@ManyToOne(fetch = FetchType.EAGER)
|
||||
private EntityD relation;
|
||||
|
||||
public EntityB() {
|
||||
}
|
||||
|
||||
public EntityB(Long id) {
|
||||
super( id );
|
||||
}
|
||||
|
||||
public void setRelation(EntityD relation) {
|
||||
this.relation = relation;
|
||||
}
|
||||
|
||||
public EntityD getRelation() {
|
||||
return relation;
|
||||
}
|
||||
|
||||
public Set<EntityD> getAttributes() {
|
||||
return attributes;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "EntityC")
|
||||
public static class EntityC {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public EntityC() {
|
||||
}
|
||||
|
||||
public EntityC(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "EntityD")
|
||||
public static class EntityD {
|
||||
@Id
|
||||
private Long id;
|
||||
|
||||
public EntityD() {
|
||||
}
|
||||
|
||||
public EntityD(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,9 +23,7 @@
|
|||
*/
|
||||
package org.hibernate.test.inheritance.discriminator;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.Id;
|
||||
|
@ -34,7 +32,7 @@ import javax.persistence.InheritanceType;
|
|||
import javax.persistence.ManyToOne;
|
||||
import javax.persistence.OneToMany;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.query.sqm.InterpretationException;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
@ -44,11 +42,6 @@ import org.junit.jupiter.api.AfterEach;
|
|||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
|
@ -105,36 +98,6 @@ public class JoinedInheritanceEagerTest {
|
|||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12375")
|
||||
public void joinFindEntity(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
EntityA entityA = session.get( EntityA.class, 4L );
|
||||
assertTrue( Hibernate.isInitialized( entityA.getRelation() ) );
|
||||
assertFalse( Hibernate.isInitialized( entityA.getAttributes() ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12375")
|
||||
public void joinFindParenEntity(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
BaseEntity baseEntity = session.get( BaseEntity.class, 4L );
|
||||
assertThat( baseEntity, notNullValue() );
|
||||
assertThat( baseEntity, instanceOf( EntityA.class ) );
|
||||
assertTrue( Hibernate.isInitialized( ( (EntityA) baseEntity ).getRelation() ) );
|
||||
assertFalse( Hibernate.isInitialized( ( (EntityA) baseEntity ).getAttributes() ) );
|
||||
} );
|
||||
|
||||
scope.inTransaction( session -> {
|
||||
BaseEntity baseEntity = session.get( BaseEntity.class, 3L );
|
||||
assertThat( baseEntity, notNullValue() );
|
||||
assertThat( baseEntity, instanceOf( EntityB.class ) );
|
||||
assertTrue( Hibernate.isInitialized( ( (EntityB) baseEntity ).getRelation() ) );
|
||||
assertFalse( Hibernate.isInitialized( ( (EntityB) baseEntity ).getAttributes() ) );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12375")
|
||||
public void joinUnrelatedCollectionOnBaseType(SessionFactoryScope scope) {
|
||||
|
@ -146,7 +109,7 @@ public class JoinedInheritanceEagerTest {
|
|||
session.createQuery( "from BaseEntity b join b.attributes" ).list();
|
||||
fail( "Expected a resolution exception for property 'attributes'!" );
|
||||
}
|
||||
catch (IllegalArgumentException ex) {
|
||||
catch (InterpretationException ex) {
|
||||
assertTrue( ex.getMessage().contains( "could not resolve property: attributes " ) );
|
||||
}
|
||||
finally {
|
||||
|
@ -157,15 +120,6 @@ public class JoinedInheritanceEagerTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-12375")
|
||||
public void selectBaseType(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
List result = session.createQuery( "from BaseEntity" ).list();
|
||||
assertEquals( result.size(), 2 );
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "BaseEntity")
|
||||
@Inheritance(strategy = InheritanceType.JOINED)
|
||||
public static class BaseEntity {
|
||||
|
|
Loading…
Reference in New Issue