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.EntityDelayedFetchImpl;
|
||||||
import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl;
|
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.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.CircularFetchImpl;
|
||||||
import org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl;
|
import org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl;
|
||||||
import org.hibernate.type.ForeignKeyDirection;
|
import org.hibernate.type.ForeignKeyDirection;
|
||||||
|
@ -167,8 +168,8 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
|
||||||
}
|
}
|
||||||
|
|
||||||
in such case the mappedBy is "primaryKey.card"
|
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
|
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.
|
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
|
// todo (6.0): find a better solution for the embeddable part name not in the NavigablePath
|
||||||
bidirectionalAttributeName = StringHelper.subStringNullIfEmpty(
|
bidirectionalAttributeName = StringHelper.subStringNullIfEmpty(
|
||||||
|
@ -399,30 +400,23 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
|
||||||
);
|
);
|
||||||
|
|
||||||
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
|
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
|
||||||
fromClauseAccess.resolveTableGroup(
|
if ( fetchParent instanceof EntityResultJoinedSubclassImpl &&
|
||||||
|
( (EntityPersister) fetchParent.getReferencedModePart() ).findDeclaredAttributeMapping( getPartName() ) == null ) {
|
||||||
|
final TableGroup tableGroupJoin = createTableGroupJoin(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
np -> {
|
lockMode,
|
||||||
final SqlAstJoinType sqlAstJoinType;
|
creationState,
|
||||||
if ( isNullable ) {
|
parentTableGroup
|
||||||
sqlAstJoinType = SqlAstJoinType.LEFT;
|
);
|
||||||
|
fromClauseAccess.registerTableGroup( fetchablePath, tableGroupJoin );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sqlAstJoinType = SqlAstJoinType.INNER;
|
fromClauseAccess.resolveTableGroup(
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
parentTableGroup,
|
np ->
|
||||||
null,
|
createTableGroupJoin( fetchablePath, lockMode, creationState, parentTableGroup )
|
||||||
sqlAstJoinType,
|
|
||||||
lockMode,
|
|
||||||
creationState.getSqlAstCreationState()
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return tableGroupJoin.getJoinedGroup();
|
|
||||||
}
|
}
|
||||||
);
|
|
||||||
|
|
||||||
creationState.registerVisitedAssociationKey( foreignKeyDescriptor.getAssociationKey() );
|
creationState.registerVisitedAssociationKey( foreignKeyDescriptor.getAssociationKey() );
|
||||||
return new EntityFetchJoinedImpl(
|
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
|
@Override
|
||||||
public int getNumberOfFetchables() {
|
public int getNumberOfFetchables() {
|
||||||
return getEntityMappingType().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;
|
package org.hibernate.test.inheritance.discriminator;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
import javax.persistence.Entity;
|
import javax.persistence.Entity;
|
||||||
import javax.persistence.FetchType;
|
import javax.persistence.FetchType;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
|
@ -34,7 +32,7 @@ import javax.persistence.InheritanceType;
|
||||||
import javax.persistence.ManyToOne;
|
import javax.persistence.ManyToOne;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
|
|
||||||
import org.hibernate.Hibernate;
|
import org.hibernate.query.sqm.InterpretationException;
|
||||||
|
|
||||||
import org.hibernate.testing.TestForIssue;
|
import org.hibernate.testing.TestForIssue;
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
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.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
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.assertTrue;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
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
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-12375")
|
@TestForIssue(jiraKey = "HHH-12375")
|
||||||
public void joinUnrelatedCollectionOnBaseType(SessionFactoryScope scope) {
|
public void joinUnrelatedCollectionOnBaseType(SessionFactoryScope scope) {
|
||||||
|
@ -146,7 +109,7 @@ public class JoinedInheritanceEagerTest {
|
||||||
session.createQuery( "from BaseEntity b join b.attributes" ).list();
|
session.createQuery( "from BaseEntity b join b.attributes" ).list();
|
||||||
fail( "Expected a resolution exception for property 'attributes'!" );
|
fail( "Expected a resolution exception for property 'attributes'!" );
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ex) {
|
catch (InterpretationException ex) {
|
||||||
assertTrue( ex.getMessage().contains( "could not resolve property: attributes " ) );
|
assertTrue( ex.getMessage().contains( "could not resolve property: attributes " ) );
|
||||||
}
|
}
|
||||||
finally {
|
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")
|
@Entity(name = "BaseEntity")
|
||||||
@Inheritance(strategy = InheritanceType.JOINED)
|
@Inheritance(strategy = InheritanceType.JOINED)
|
||||||
public static class BaseEntity {
|
public static class BaseEntity {
|
||||||
|
|
Loading…
Reference in New Issue