HHH-16191 Add test and fix checks for skipping resolving polymorphic associated entity instances
This commit is contained in:
parent
10bfcabee2
commit
8312db1b9e
|
@ -78,15 +78,15 @@ public interface Initializer {
|
||||||
default boolean isAttributeAssignableToConcreteDescriptor(
|
default boolean isAttributeAssignableToConcreteDescriptor(
|
||||||
FetchParentAccess parentAccess,
|
FetchParentAccess parentAccess,
|
||||||
AttributeMapping referencedModelPart) {
|
AttributeMapping referencedModelPart) {
|
||||||
if ( parentAccess != null && parentAccess.isEntityInitializer() ) {
|
final EntityInitializer entityInitializer = parentAccess == null ?
|
||||||
final EntityPersister concreteDescriptor = parentAccess.findFirstEntityInitializer()
|
null :
|
||||||
.getConcreteDescriptor();
|
parentAccess.findFirstEntityInitializer();
|
||||||
|
if ( entityInitializer != null ) {
|
||||||
|
final EntityPersister concreteDescriptor = entityInitializer.getConcreteDescriptor();
|
||||||
if ( concreteDescriptor.getEntityMetamodel().isPolymorphic() ) {
|
if ( concreteDescriptor.getEntityMetamodel().isPolymorphic() ) {
|
||||||
final EntityPersister declaringType = (EntityPersister) referencedModelPart.getDeclaringType();
|
final EntityPersister declaringType = (EntityPersister) referencedModelPart.getDeclaringType();
|
||||||
if ( concreteDescriptor != declaringType ) {
|
if ( concreteDescriptor != declaringType ) {
|
||||||
if ( !declaringType.getSubclassEntityNames().contains( concreteDescriptor.getEntityName() ) ) {
|
return declaringType.getSubclassEntityNames().contains( concreteDescriptor.getEntityName() );
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,7 +98,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
private EntityKey entityKey;
|
private EntityKey entityKey;
|
||||||
private Object entityInstance;
|
private Object entityInstance;
|
||||||
private Object entityInstanceForNotify;
|
private Object entityInstanceForNotify;
|
||||||
private boolean missing;
|
protected boolean missing;
|
||||||
boolean isInitialized;
|
boolean isInitialized;
|
||||||
private boolean isOwningInitializer;
|
private boolean isOwningInitializer;
|
||||||
private Object[] resolvedEntityState;
|
private Object[] resolvedEntityState;
|
||||||
|
@ -399,26 +399,44 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean shouldSkipResolveInstance(RowProcessingState rowProcessingState) {
|
protected boolean shouldSkipResolveInstance(RowProcessingState rowProcessingState) {
|
||||||
final NavigablePath parent = navigablePath.getParent();
|
if ( navigablePath.getParent() != null ) {
|
||||||
if ( parent != null ) {
|
Initializer parentInitializer = rowProcessingState.resolveInitializer( navigablePath.getParent() );
|
||||||
final Initializer parentInitializer = rowProcessingState.resolveInitializer( parent );
|
if ( parentInitializer != null ) {
|
||||||
if ( parentInitializer != null && parentInitializer.isEntityInitializer() ) {
|
ModelPart modelPart = referencedModelPart;
|
||||||
if ( isReferencedModelPartAssignableToConcreteParent( parentInitializer ) ) {
|
NavigablePath currentNavigablePath = navigablePath;
|
||||||
return true;
|
// Walk back initializers until we find an EntityInitializer
|
||||||
|
while ( parentInitializer != null && !parentInitializer.isEntityInitializer() ) {
|
||||||
|
modelPart = parentInitializer.getInitializedPart();
|
||||||
|
currentNavigablePath = currentNavigablePath.getParent();
|
||||||
|
parentInitializer = rowProcessingState.resolveInitializer( currentNavigablePath.getParent() );
|
||||||
|
}
|
||||||
|
if ( parentInitializer != null && parentInitializer.asEntityInitializer()
|
||||||
|
.getEntityDescriptor()
|
||||||
|
.getEntityMetamodel()
|
||||||
|
.isPolymorphic() ) {
|
||||||
|
parentInitializer.resolveKey( rowProcessingState );
|
||||||
|
return isReferencedModelPartInConcreteParent(
|
||||||
|
modelPart,
|
||||||
|
currentNavigablePath,
|
||||||
|
parentInitializer
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isReferencedModelPartAssignableToConcreteParent(Initializer parentInitializer) {
|
private boolean isReferencedModelPartInConcreteParent(
|
||||||
|
ModelPart modelPart,
|
||||||
|
NavigablePath partNavigablePath,
|
||||||
|
Initializer parentInitializer) {
|
||||||
final EntityPersister parentConcreteDescriptor = parentInitializer.asEntityInitializer()
|
final EntityPersister parentConcreteDescriptor = parentInitializer.asEntityInitializer()
|
||||||
.getConcreteDescriptor();
|
.getConcreteDescriptor();
|
||||||
if ( parentConcreteDescriptor != null && parentConcreteDescriptor.getEntityMetamodel().isPolymorphic() ) {
|
if ( parentConcreteDescriptor != null && parentConcreteDescriptor.getEntityMetamodel().isPolymorphic() ) {
|
||||||
final ModelPart concreteModelPart = parentConcreteDescriptor.findByPath( navigablePath.getLocalName() );
|
final ModelPart concreteModelPart = parentConcreteDescriptor.findByPath( partNavigablePath.getLocalName() );
|
||||||
if ( concreteModelPart == null
|
if ( concreteModelPart == null
|
||||||
|| !referencedModelPart.getJavaType().getJavaTypeClass()
|
|| !modelPart.getJavaType().getJavaTypeClass()
|
||||||
.isAssignableFrom( concreteModelPart.getJavaType().getJavaTypeClass() ) ) {
|
.isAssignableFrom( concreteModelPart.getJavaType().getJavaTypeClass() ) ) {
|
||||||
/*
|
/*
|
||||||
Given:
|
Given:
|
||||||
|
|
|
@ -71,6 +71,11 @@ public class EntityJoinedFetchInitializer extends AbstractEntityInitializer {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resolveKey(RowProcessingState rowProcessingState) {
|
public void resolveKey(RowProcessingState rowProcessingState) {
|
||||||
|
if ( shouldSkipResolveInstance( rowProcessingState ) ) {
|
||||||
|
missing = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
super.resolveKey( rowProcessingState );
|
super.resolveKey( rowProcessingState );
|
||||||
|
|
||||||
// super processes the foreign-key target column. here we
|
// super processes the foreign-key target column. here we
|
||||||
|
|
|
@ -67,10 +67,8 @@ public class LoadANonExistingNotFoundEntityTest extends BaseNonConfigCoreFunctio
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// The Employee#employer must be initialized immediately because
|
// we should get 1 query for the Employee with join
|
||||||
// enhanced proxies (and HibernateProxy objects) should never be created
|
assertEquals( 1, statistics.getPrepareStatementCount() );
|
||||||
// for a "not found" association.
|
|
||||||
assertEquals( 2, statistics.getPrepareStatementCount() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -86,10 +84,8 @@ public class LoadANonExistingNotFoundEntityTest extends BaseNonConfigCoreFunctio
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
// The Employee#employer must be initialized immediately because
|
// we should get 1 query for the Employee with join
|
||||||
// enhanced proxies (and HibernateProxy objects) should never be created
|
assertEquals( 1, statistics.getPrepareStatementCount() );
|
||||||
// for a "not found" association.
|
|
||||||
assertEquals( 2, statistics.getPrepareStatementCount() );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -178,7 +174,7 @@ public class LoadANonExistingNotFoundEntityTest extends BaseNonConfigCoreFunctio
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
|
@ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
|
||||||
@JoinColumn(name = "employer_id",foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
@JoinColumn(name = "employer_id",foreignKey = @ForeignKey(value= ConstraintMode.NO_CONSTRAINT))
|
||||||
@NotFound(action=NotFoundAction.IGNORE)
|
@NotFound(action=NotFoundAction.IGNORE)
|
||||||
private Employer employer;
|
private Employer employer;
|
||||||
|
|
|
@ -7,10 +7,6 @@
|
||||||
package org.hibernate.orm.test.inheritance;
|
package org.hibernate.orm.test.inheritance;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.annotations.NotFound;
|
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
import jakarta.persistence.DiscriminatorColumn;
|
import jakarta.persistence.DiscriminatorColumn;
|
||||||
|
@ -307,7 +303,6 @@ public class TransientOverrideAsPersistentMappedSuperclass {
|
||||||
// Editor#title (which uses the same e_title column) can be non-null,
|
// Editor#title (which uses the same e_title column) can be non-null,
|
||||||
// and there is no associated group.
|
// and there is no associated group.
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@NotFound(action = NotFoundAction.IGNORE)
|
|
||||||
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||||
public Group getGroup() {
|
public Group getGroup() {
|
||||||
return group;
|
return group;
|
||||||
|
|
|
@ -7,10 +7,6 @@
|
||||||
package org.hibernate.orm.test.inheritance;
|
package org.hibernate.orm.test.inheritance;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.annotations.NotFound;
|
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
import jakarta.persistence.DiscriminatorColumn;
|
import jakarta.persistence.DiscriminatorColumn;
|
||||||
|
@ -300,7 +296,6 @@ public class TransientOverrideAsPersistentSingleTable {
|
||||||
// Editor#title (which uses the same e_title column) can be non-null,
|
// Editor#title (which uses the same e_title column) can be non-null,
|
||||||
// and there is no associated group.
|
// and there is no associated group.
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@NotFound(action = NotFoundAction.IGNORE)
|
|
||||||
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||||
public Group getGroup() {
|
public Group getGroup() {
|
||||||
return group;
|
return group;
|
||||||
|
|
|
@ -8,10 +8,6 @@ package org.hibernate.orm.test.inheritance;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.annotations.NotFound;
|
|
||||||
import org.hibernate.annotations.NotFoundAction;
|
|
||||||
|
|
||||||
import jakarta.persistence.Column;
|
import jakarta.persistence.Column;
|
||||||
import jakarta.persistence.ConstraintMode;
|
import jakarta.persistence.ConstraintMode;
|
||||||
import jakarta.persistence.DiscriminatorColumn;
|
import jakarta.persistence.DiscriminatorColumn;
|
||||||
|
@ -303,7 +299,6 @@ public class TransientOverrideAsPersistentTablePerClass {
|
||||||
// Editor#title (which uses the same e_title column) can be non-null,
|
// Editor#title (which uses the same e_title column) can be non-null,
|
||||||
// and there is no associated group.
|
// and there is no associated group.
|
||||||
@ManyToOne(optional = false)
|
@ManyToOne(optional = false)
|
||||||
@NotFound(action = NotFoundAction.IGNORE)
|
|
||||||
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||||
public Group getGroup() {
|
public Group getGroup() {
|
||||||
return group;
|
return group;
|
||||||
|
|
|
@ -0,0 +1,411 @@
|
||||||
|
/*
|
||||||
|
* 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.inheritance;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
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 jakarta.persistence.Column;
|
||||||
|
import jakarta.persistence.ConstraintMode;
|
||||||
|
import jakarta.persistence.DiscriminatorColumn;
|
||||||
|
import jakarta.persistence.Embeddable;
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.ForeignKey;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Inheritance;
|
||||||
|
import jakarta.persistence.InheritanceType;
|
||||||
|
import jakarta.persistence.JoinColumn;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import jakarta.persistence.MappedSuperclass;
|
||||||
|
import jakarta.persistence.OneToOne;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import jakarta.persistence.Transient;
|
||||||
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
import jakarta.persistence.criteria.ParameterExpression;
|
||||||
|
import jakarta.persistence.criteria.Predicate;
|
||||||
|
import jakarta.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||||
|
|
||||||
|
@TestForIssue(jiraKey = "HHH-14103")
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
TransientOverrideAsPersistentWithEmbeddable.Employee.class,
|
||||||
|
TransientOverrideAsPersistentWithEmbeddable.Editor.class,
|
||||||
|
TransientOverrideAsPersistentWithEmbeddable.Writer.class,
|
||||||
|
TransientOverrideAsPersistentWithEmbeddable.Group.class,
|
||||||
|
TransientOverrideAsPersistentWithEmbeddable.Job.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
public class TransientOverrideAsPersistentWithEmbeddable {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindByRootClass(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final Employee editor = session.find( Employee.class, "Jane Smith" );
|
||||||
|
assertNotNull( editor );
|
||||||
|
assertEquals( "Senior Editor", editor.getTitle() );
|
||||||
|
final Employee writer = session.find( Employee.class, "John Smith" );
|
||||||
|
assertThat( writer, instanceOf( Writer.class ) );
|
||||||
|
assertEquals( "Writing", writer.getTitle() );
|
||||||
|
assertNotNull( ( (Writer) writer ).getWriterEmbeddable().getGroup() );
|
||||||
|
final Group group = ( (Writer) writer ).getWriterEmbeddable().getGroup();
|
||||||
|
assertEquals( writer.getTitle(), group.getName() );
|
||||||
|
final Job jobEditor = session.find( Job.class, "Edit" );
|
||||||
|
assertSame( editor, jobEditor.getEmployee() );
|
||||||
|
final Job jobWriter = session.find( Job.class, "Write" );
|
||||||
|
assertSame( writer, jobWriter.getEmployee() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFindBySubclass(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final Editor editor = session.find( Editor.class, "Jane Smith" );
|
||||||
|
assertNotNull( editor );
|
||||||
|
assertEquals( "Senior Editor", editor.getTitle() );
|
||||||
|
final Writer writer = session.find( Writer.class, "John Smith" );
|
||||||
|
assertEquals( "Writing", writer.getTitle() );
|
||||||
|
assertNotNull( writer.getWriterEmbeddable().getGroup() );
|
||||||
|
final Group group = writer.getWriterEmbeddable().getGroup();
|
||||||
|
assertEquals( writer.getTitle(), group.getName() );
|
||||||
|
final Job jobEditor = session.find( Job.class, "Edit" );
|
||||||
|
assertSame( editor, jobEditor.getEmployee() );
|
||||||
|
final Job jobWriter = session.find( Job.class, "Write" );
|
||||||
|
assertSame( writer, jobWriter.getEmployee() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryByRootClass(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final List<Employee> employees = session.createQuery( "from Employee", Employee.class )
|
||||||
|
.getResultList();
|
||||||
|
assertEquals( 2, employees.size() );
|
||||||
|
assertThat( employees.get( 0 ), instanceOf( Editor.class ) );
|
||||||
|
assertThat( employees.get( 1 ), instanceOf( Writer.class ) );
|
||||||
|
final Editor editor = (Editor) employees.get( 0 );
|
||||||
|
assertEquals( "Senior Editor", editor.getTitle() );
|
||||||
|
final Writer writer = (Writer) employees.get( 1 );
|
||||||
|
assertEquals( "Writing", writer.getTitle() );
|
||||||
|
assertNotNull( writer.getWriterEmbeddable().getGroup() );
|
||||||
|
final Group group = writer.getWriterEmbeddable().getGroup();
|
||||||
|
assertEquals( writer.getTitle(), group.getName() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryByRootClassAndOverridenProperty(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final Employee editor = session.createQuery( "from Employee where title=:title", Employee.class )
|
||||||
|
.setParameter( "title", "Senior Editor" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertThat( editor, instanceOf( Editor.class ) );
|
||||||
|
|
||||||
|
final Employee writer = session.createQuery( "from Employee where title=:title", Employee.class )
|
||||||
|
.setParameter( "title", "Writing" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertThat( writer, instanceOf( Writer.class ) );
|
||||||
|
assertNotNull( ( (Writer) writer ).getWriterEmbeddable().getGroup() );
|
||||||
|
assertEquals( writer.getTitle(), ( (Writer) writer ).getWriterEmbeddable().getGroup().getName() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryByRootClassAndOverridenPropertyTreat(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final Employee editor = session.createQuery(
|
||||||
|
"from Employee e where treat( e as Editor ).title=:title",
|
||||||
|
Employee.class
|
||||||
|
)
|
||||||
|
.setParameter( "title", "Senior Editor" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertThat( editor, instanceOf( Editor.class ) );
|
||||||
|
|
||||||
|
final Employee writer = session.createQuery(
|
||||||
|
"from Employee e where treat( e as Writer).title=:title",
|
||||||
|
Employee.class
|
||||||
|
)
|
||||||
|
.setParameter( "title", "Writing" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertThat( writer, instanceOf( Writer.class ) );
|
||||||
|
assertNotNull( ( (Writer) writer ).getWriterEmbeddable().getGroup() );
|
||||||
|
assertEquals( writer.getTitle(), ( (Writer) writer ).getWriterEmbeddable().getGroup().getName() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testQueryBySublassAndOverridenProperty(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final Editor editor = session.createQuery( "from Editor where title=:title", Editor.class )
|
||||||
|
.setParameter( "title", "Senior Editor" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertThat( editor, instanceOf( Editor.class ) );
|
||||||
|
|
||||||
|
final Writer writer = session.createQuery( "from Writer where title=:title", Writer.class )
|
||||||
|
.setParameter( "title", "Writing" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertNotNull( writer.getWriterEmbeddable().getGroup() );
|
||||||
|
assertEquals( writer.getTitle(), writer.getWriterEmbeddable().getGroup().getName() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCriteriaQueryByRootClassAndOverridenProperty(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
|
||||||
|
final CriteriaBuilder builder = session.getCriteriaBuilder();
|
||||||
|
|
||||||
|
final CriteriaQuery<Employee> query = builder.createQuery( Employee.class );
|
||||||
|
final Root<Employee> root = query.from( Employee.class );
|
||||||
|
final ParameterExpression<String> parameter = builder.parameter( String.class, "title" );
|
||||||
|
|
||||||
|
final Predicate predicateEditor = builder.equal(
|
||||||
|
builder.treat( root, Editor.class ).get( "title" ),
|
||||||
|
parameter
|
||||||
|
);
|
||||||
|
query.where( predicateEditor );
|
||||||
|
final Employee editor = session.createQuery( query )
|
||||||
|
.setParameter( "title", "Senior Editor" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertThat( editor, instanceOf( Editor.class ) );
|
||||||
|
|
||||||
|
final Predicate predicateWriter = builder.equal(
|
||||||
|
builder.treat( root, Writer.class ).get( "title" ),
|
||||||
|
parameter
|
||||||
|
);
|
||||||
|
query.where( predicateWriter );
|
||||||
|
final Employee writer = session.createQuery( query )
|
||||||
|
.setParameter( "title", "Writing" )
|
||||||
|
.getSingleResult();
|
||||||
|
assertThat( writer, instanceOf( Writer.class ) );
|
||||||
|
assertNotNull( ( (Writer) writer ).getWriterEmbeddable().getGroup() );
|
||||||
|
assertEquals( writer.getTitle(), ( (Writer) writer ).getWriterEmbeddable().getGroup().getName() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void setupData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
Job jobEditor = new Job( "Edit" );
|
||||||
|
jobEditor.setEmployee( new Editor( "Jane Smith", "Senior Editor" ) );
|
||||||
|
Job jobWriter = new Job( "Write" );
|
||||||
|
jobWriter.setEmployee( new Writer( "John Smith", new Group( "Writing" ) ) );
|
||||||
|
|
||||||
|
Employee editor = jobEditor.getEmployee();
|
||||||
|
Employee writer = jobWriter.getEmployee();
|
||||||
|
Group group = Writer.class.cast( writer ).getWriterEmbeddable().getGroup();
|
||||||
|
|
||||||
|
session.persist( editor );
|
||||||
|
session.persist( group );
|
||||||
|
session.persist( writer );
|
||||||
|
session.persist( jobEditor );
|
||||||
|
session.persist( jobWriter );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void cleanupData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
session.createQuery( "delete from Job" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||||
|
session.createQuery( "delete from Group" ).executeUpdate();
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@MappedSuperclass
|
||||||
|
public static class AbstractEmployee {
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@Transient
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setTitle(String title) {
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Employee")
|
||||||
|
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
|
||||||
|
@DiscriminatorColumn(name = "department")
|
||||||
|
public static abstract class Employee extends AbstractEmployee {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
protected Employee(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Employee() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Editor")
|
||||||
|
public static class Editor extends Employee {
|
||||||
|
public Editor(String name, String title) {
|
||||||
|
super( name );
|
||||||
|
setTitle( title );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Column(name = "e_title")
|
||||||
|
public String getTitle() {
|
||||||
|
return super.getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
super.setTitle( title );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Editor() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Embeddable
|
||||||
|
public static class WriterEmbeddable {
|
||||||
|
private Group group;
|
||||||
|
|
||||||
|
// Cannot have a constraint on e_title because
|
||||||
|
// Editor#title (which uses the same e_title column) can be non-null,
|
||||||
|
// and there is no associated group.
|
||||||
|
@ManyToOne(optional = false)
|
||||||
|
@JoinColumn(name = "e_title", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
|
||||||
|
public Group getGroup() {
|
||||||
|
return group;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGroup(Group group) {
|
||||||
|
this.group = group;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Writer")
|
||||||
|
public static class Writer extends Employee {
|
||||||
|
private WriterEmbeddable writerEmbeddable;
|
||||||
|
|
||||||
|
public Writer(String name, Group group) {
|
||||||
|
super( name );
|
||||||
|
this.writerEmbeddable = new WriterEmbeddable();
|
||||||
|
setGroup( group );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Column(name = "e_title", insertable = false, updatable = false)
|
||||||
|
public String getTitle() {
|
||||||
|
return super.getTitle();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTitle(String title) {
|
||||||
|
super.setTitle( title );
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Writer() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setGroup(Group group) {
|
||||||
|
this.writerEmbeddable.setGroup( group );
|
||||||
|
setTitle( group.getName() );
|
||||||
|
}
|
||||||
|
|
||||||
|
public WriterEmbeddable getWriterEmbeddable() {
|
||||||
|
return writerEmbeddable;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setWriterEmbeddable(WriterEmbeddable writerEmbeddable) {
|
||||||
|
this.writerEmbeddable = writerEmbeddable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Group")
|
||||||
|
@Table(name = "WorkGroup")
|
||||||
|
public static class Group {
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private String desctiption;
|
||||||
|
|
||||||
|
public Group(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Group() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity(name = "Job")
|
||||||
|
public static class Job {
|
||||||
|
private String name;
|
||||||
|
private Employee employee;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
public Job(String name) {
|
||||||
|
this();
|
||||||
|
setName( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@OneToOne
|
||||||
|
@JoinColumn(name = "employee_name")
|
||||||
|
public Employee getEmployee() {
|
||||||
|
return employee;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Job() {
|
||||||
|
// this form used by Hibernate
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setEmployee(Employee e) {
|
||||||
|
this.employee = e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue