mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-27 14:30:16 +00:00
Inhetirance : Fix stack overflow for Queryable#findSubPart and wrong value for Lockable#getRootTableName()
This commit is contained in:
parent
ba830d5ad5
commit
25fc3e2dce
@ -33,6 +33,19 @@ public interface Queryable extends ModelPart {
|
||||
*/
|
||||
ModelPart findSubPart(String name, EntityMappingType treatTargetType);
|
||||
|
||||
/**
|
||||
* For an entity, this form allows for Hibernate's "implicit treat" support -
|
||||
* meaning it should find a sub-part whether defined on the entity or one of its sub-types.
|
||||
*
|
||||
* @implNote Logically the implementation should consider
|
||||
* {@link org.hibernate.jpa.spi.JpaCompliance}. Not passed in because it
|
||||
* is expected that implementors have access to the SessionFactory to access
|
||||
* the JpaCompliance. See {@link SessionFactoryOptions#getJpaCompliance}
|
||||
*/
|
||||
default ModelPart findSubTypesSubPart(String name, EntityMappingType treatTargetType) {
|
||||
return findSubPart( name, treatTargetType );
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #findSubPart}, this form visits all parts defined on the
|
||||
* entity, its super-types and its sub-types.
|
||||
|
@ -150,6 +150,25 @@ public PersistentAttribute<? super J,?> findAttribute(String name) {
|
||||
}
|
||||
}
|
||||
|
||||
for ( ManagedDomainType subType : subTypes ) {
|
||||
PersistentAttribute subTypeAttribute = subType.findSubTypesAttribute( name );
|
||||
if ( subTypeAttribute != null ) {
|
||||
return subTypeAttribute;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public PersistentAttribute<? super J, ?> findSubTypesAttribute(String name) {
|
||||
// first look at declared attributes
|
||||
PersistentAttribute attribute = findDeclaredAttribute( name );
|
||||
if ( attribute != null ) {
|
||||
return attribute;
|
||||
}
|
||||
|
||||
for ( ManagedDomainType subType : subTypes ) {
|
||||
PersistentAttribute subTypeAttribute = subType.findAttribute( name );
|
||||
if ( subTypeAttribute != null ) {
|
||||
|
@ -51,6 +51,9 @@ public interface ManagedDomainType<J> extends SimpleDomainType<J>, ManagedType<J
|
||||
PersistentAttribute<J,?> getDeclaredAttribute(String name);
|
||||
|
||||
PersistentAttribute<? super J,?> findAttribute(String name);
|
||||
|
||||
PersistentAttribute<? super J, ?> findSubTypesAttribute(String name);
|
||||
|
||||
SingularPersistentAttribute<? super J,?> findSingularAttribute(String name);
|
||||
PluralPersistentAttribute<? super J, ?,?> findPluralAttribute(String name);
|
||||
|
||||
|
@ -1204,7 +1204,7 @@ public String getSqlAliasStem() {
|
||||
|
||||
@Override
|
||||
public boolean containsTableReference(String tableExpression) {
|
||||
if ( getRootTableName().equals( tableExpression ) ) {
|
||||
if ( getTableName().equals( tableExpression ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -1347,7 +1347,7 @@ public TableReferenceJoin createTableReferenceJoin(
|
||||
|
||||
protected TableReference resolvePrimaryTableReference(SqlAliasBase sqlAliasBase) {
|
||||
return new TableReference(
|
||||
getRootTableName(),
|
||||
getTableName(),
|
||||
sqlAliasBase.generateNewAlias(),
|
||||
false,
|
||||
getFactory()
|
||||
@ -5839,7 +5839,7 @@ public void prepareMappingModel(MappingModelCreationProcess creationProcess) {
|
||||
else {
|
||||
rowIdMapping = creationProcess.processSubPart(
|
||||
rowIdName,
|
||||
(role, creationProcess1) -> new EntityRowIdMappingImpl( rowIdName, this.getRootTableName(), this)
|
||||
(role, creationProcess1) -> new EntityRowIdMappingImpl( rowIdName, this.getTableName(), this)
|
||||
);
|
||||
}
|
||||
|
||||
@ -5953,7 +5953,7 @@ protected void buildDiscriminatorMapping() {
|
||||
else {
|
||||
discriminatorMapping = new EntityDiscriminatorMappingImpl(
|
||||
this,
|
||||
getRootTableName(),
|
||||
getTableName(),
|
||||
getDiscriminatorColumnReaders(),
|
||||
(BasicType) getDiscriminatorType()
|
||||
);
|
||||
@ -6049,7 +6049,7 @@ private EntityIdentifierMapping generateIdentifierMapping(MappingModelCreationPr
|
||||
this,
|
||||
bootEntityDescriptor.getIdentifierProperty(),
|
||||
bootEntityDescriptor.getIdentifierProperty().getName(),
|
||||
getRootTableName(),
|
||||
getTableName(),
|
||||
rootTableKeyColumnNames,
|
||||
cidType,
|
||||
creationProcess
|
||||
@ -6062,7 +6062,7 @@ private EntityIdentifierMapping generateIdentifierMapping(MappingModelCreationPr
|
||||
|
||||
return new BasicEntityIdentifierMappingImpl(
|
||||
this,
|
||||
getRootTableName(),
|
||||
getTableName(),
|
||||
rootTableKeyColumnNames[0],
|
||||
(BasicType) idType,
|
||||
creationProcess
|
||||
@ -6077,7 +6077,7 @@ private EntityIdentifierMapping generateNonEncapsulatedCompositeIdentifierMappin
|
||||
|
||||
return MappingModelCreationHelper.buildNonEncapsulatedCompositeIdentifierMapping(
|
||||
this,
|
||||
getRootTableName(),
|
||||
getTableName(),
|
||||
getRootTableKeyColumnNames(),
|
||||
cidType,
|
||||
bootEntityDescriptor,
|
||||
@ -6107,7 +6107,7 @@ private static EntityVersionMapping generateVersionMapping(
|
||||
|
||||
return new EntityVersionMappingImpl(
|
||||
bootModelRootEntityDescriptor.getVersion().getName(),
|
||||
entityPersister.getRootTableName(),
|
||||
entityPersister.getTableName(),
|
||||
versionColumnName,
|
||||
basicTypeResolution.getLegacyResolvedBasicType(),
|
||||
entityPersister
|
||||
@ -6301,14 +6301,38 @@ public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( subclassMappingTypes != null && ! subclassMappingTypes.isEmpty() ) {
|
||||
if ( subclassMappingTypes != null && !subclassMappingTypes.isEmpty() ) {
|
||||
for ( EntityMappingType subMappingType : subclassMappingTypes.values() ) {
|
||||
final ModelPart subDefinedAttribute = subMappingType.findSubPart( name, treatTargetType );
|
||||
final ModelPart subDefinedAttribute = subMappingType.findSubTypesSubPart( name, treatTargetType );
|
||||
|
||||
if ( subDefinedAttribute != null ) {
|
||||
return subDefinedAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart findSubTypesSubPart(String name, EntityMappingType treatTargetType) {
|
||||
if ( isIdentifierReference( name ) ) {
|
||||
return identifierMapping;
|
||||
}
|
||||
|
||||
final AttributeMapping declaredAttribute = declaredAttributeMappings.get( name );
|
||||
if ( declaredAttribute != null ) {
|
||||
return declaredAttribute;
|
||||
}
|
||||
|
||||
if ( subclassMappingTypes != null && !subclassMappingTypes.isEmpty() ) {
|
||||
for ( EntityMappingType subMappingType : subclassMappingTypes.values() ) {
|
||||
final ModelPart subDefinedAttribute = subMappingType.findSubTypesSubPart( name, treatTargetType );
|
||||
|
||||
if ( subDefinedAttribute != null ) {
|
||||
return subDefinedAttribute;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
|
@ -1022,6 +1022,11 @@ public String[] getIdentifierColumnReaderTemplates() {
|
||||
return tableKeyColumnReaderTemplates[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRootTableName() {
|
||||
return naturalOrderTableNames[0];
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaders() {
|
||||
return tableKeyColumnReaders[0];
|
||||
}
|
||||
@ -1241,7 +1246,7 @@ public EntityDiscriminatorMapping getDiscriminatorMapping(TableGroup tableGroup)
|
||||
CaseSearchedExpressionInfo info = getCaseSearchedExpression( tableGroup );
|
||||
return new JoinedSubclassDiscriminatorMappingImpl(
|
||||
this,
|
||||
getRootTableName(),
|
||||
getTableName(),
|
||||
getDiscriminatorColumnName(),
|
||||
info.caseSearchedExpression,
|
||||
info.columnReferences,
|
||||
|
@ -150,6 +150,10 @@ public PersistentAttribute findAttribute(String name) {
|
||||
return commonAttributes.get( name );
|
||||
}
|
||||
|
||||
public PersistentAttribute findSubTypesAttribute(String name) {
|
||||
return commonAttributes.get( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitAttributes(Consumer<PersistentAttribute<T, ?>> action) {
|
||||
commonAttributes.values().forEach( (Consumer) action );
|
||||
|
@ -0,0 +1,19 @@
|
||||
/*
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
//$Id: Address.java 4364 2004-08-17 12:10:32Z oneovthafew $
|
||||
package org.hibernate.orm.test.joinedsubclass;
|
||||
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Address {
|
||||
public String address;
|
||||
public String zip;
|
||||
public String country;
|
||||
}
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
//$Id: Customer.java 4364 2004-08-17 12:10:32Z oneovthafew $
|
||||
package org.hibernate.orm.test.joinedsubclass;
|
||||
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Customer extends Person {
|
||||
private Employee salesperson;
|
||||
private String comments;
|
||||
|
||||
/**
|
||||
* @return Returns the salesperson.
|
||||
*/
|
||||
public Employee getSalesperson() {
|
||||
return salesperson;
|
||||
}
|
||||
/**
|
||||
* @param salesperson The salesperson to set.
|
||||
*/
|
||||
public void setSalesperson(Employee salesperson) {
|
||||
this.salesperson = salesperson;
|
||||
}
|
||||
/**
|
||||
* @return Returns the comments.
|
||||
*/
|
||||
public String getComments() {
|
||||
return comments;
|
||||
}
|
||||
/**
|
||||
* @param comments The comments to set.
|
||||
*/
|
||||
public void setComments(String comments) {
|
||||
this.comments = comments;
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
//$Id: Employee.java 4364 2004-08-17 12:10:32Z oneovthafew $
|
||||
package org.hibernate.orm.test.joinedsubclass;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Employee extends Person {
|
||||
private String title;
|
||||
private BigDecimal salary;
|
||||
private double passwordExpiryDays;
|
||||
private Employee manager;
|
||||
/**
|
||||
* @return Returns the title.
|
||||
*/
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
/**
|
||||
* @param title The title to set.
|
||||
*/
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
/**
|
||||
* @return Returns the manager.
|
||||
*/
|
||||
public Employee getManager() {
|
||||
return manager;
|
||||
}
|
||||
/**
|
||||
* @param manager The manager to set.
|
||||
*/
|
||||
public void setManager(Employee manager) {
|
||||
this.manager = manager;
|
||||
}
|
||||
/**
|
||||
* @return Returns the salary.
|
||||
*/
|
||||
public BigDecimal getSalary() {
|
||||
return salary;
|
||||
}
|
||||
/**
|
||||
* @param salary The salary to set.
|
||||
*/
|
||||
public void setSalary(BigDecimal salary) {
|
||||
this.salary = salary;
|
||||
}
|
||||
/**
|
||||
* @return The password expiry policy in days.
|
||||
*/
|
||||
public double getPasswordExpiryDays() {
|
||||
return passwordExpiryDays;
|
||||
}
|
||||
/**
|
||||
* @param passwordExpiryDays The password expiry policy in days.
|
||||
*/
|
||||
public void setPasswordExpiryDays(double passwordExpiryDays) {
|
||||
this.passwordExpiryDays = passwordExpiryDays;
|
||||
}
|
||||
}
|
@ -0,0 +1,163 @@
|
||||
/*
|
||||
* 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.joinedsubclass;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
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.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertSame;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
@DomainModel(
|
||||
xmlMappings = "org/hibernate/orm/test/joinedsubclass/Person.hbm.xml"
|
||||
)
|
||||
@SessionFactory
|
||||
public class JoinedSubclassTest {
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||
session.createQuery( "delete from Customer" ).executeUpdate();
|
||||
session.createQuery( "delete from Person" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAccessAsIncorrectSubclass(SessionFactoryScope scope) {
|
||||
final Employee e = new Employee();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
e.setName( "Steve" );
|
||||
e.setSex( 'M' );
|
||||
e.setTitle( "grand poobah" );
|
||||
session.save( e );
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Customer c = scope.fromTransaction(
|
||||
session ->
|
||||
session.get( Customer.class, new Long( e.getId() ) )
|
||||
|
||||
);
|
||||
assertNull( c );
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
Employee employee = session.get( Employee.class, new Long( e.getId() ) );
|
||||
Customer customer = session.get( Customer.class, new Long( e.getId() ) );
|
||||
assertNotNull( employee );
|
||||
assertNull( customer );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.delete( e );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuerySubclassAttribute(SessionFactoryScope scope) {
|
||||
scope.inTransaction( s -> {
|
||||
Person p = new Person();
|
||||
p.setName( "Emmanuel" );
|
||||
p.setSex( 'M' );
|
||||
s.persist( p );
|
||||
Employee q = new Employee();
|
||||
q.setName( "Steve" );
|
||||
q.setSex( 'M' );
|
||||
q.setTitle( "Mr" );
|
||||
q.setSalary( new BigDecimal( 1000 ) );
|
||||
s.persist( q );
|
||||
|
||||
List result = s.createQuery( "from Person where salary > 100" ).list();
|
||||
assertEquals( result.size(), 1 );
|
||||
assertSame( result.get( 0 ), q );
|
||||
|
||||
result = s.createQuery( "from Person where salary > 100 or name like 'E%'" ).list();
|
||||
assertEquals( result.size(), 2 );
|
||||
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
|
||||
criteria.where( criteriaBuilder.gt( root.get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
|
||||
result = s.createQuery( criteria ).list();
|
||||
// result = s.createCriteria( Person.class )
|
||||
// .add( Property.forName( "salary" ).gt( new BigDecimal( 100 ) ) )
|
||||
// .list();
|
||||
assertEquals( result.size(), 1 );
|
||||
assertSame( result.get( 0 ), q );
|
||||
|
||||
//TODO: make this work:
|
||||
/*result = s.createQuery("select salary from Person where salary > 100").list();
|
||||
assertEquals( result.size(), 1 );
|
||||
assertEquals( result.get(0), new BigDecimal(1000) );*/
|
||||
|
||||
s.delete( p );
|
||||
s.delete( q );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockingJoinedSubclass(SessionFactoryScope scope) {
|
||||
Person p = new Person();
|
||||
Employee q = new Employee();
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
p.setName( "Emmanuel" );
|
||||
p.setSex( 'M' );
|
||||
session.persist( p );
|
||||
q.setName( "Steve" );
|
||||
q.setSex( 'M' );
|
||||
q.setTitle( "Mr" );
|
||||
q.setSalary( new BigDecimal( 1000 ) );
|
||||
session.persist( q );
|
||||
}
|
||||
);
|
||||
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.lock( p, LockMode.UPGRADE );
|
||||
session.lock( q, LockMode.UPGRADE );
|
||||
session.delete( p );
|
||||
session.delete( q );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,82 @@
|
||||
<?xml version="1.0"?>
|
||||
<!--
|
||||
~ 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>.
|
||||
-->
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||
|
||||
<!--
|
||||
|
||||
This mapping demonstrates
|
||||
|
||||
(1) a table-per-subclass mapping strategy
|
||||
|
||||
(2) a simple component mapping
|
||||
|
||||
(3) recursive associations withing an inheritance tree
|
||||
|
||||
-->
|
||||
|
||||
<hibernate-mapping
|
||||
package="org.hibernate.orm.test.joinedsubclass"
|
||||
default-access="field">
|
||||
|
||||
<class name="Person" table="JPerson">
|
||||
|
||||
<id name="id"
|
||||
column="person_id"
|
||||
unsaved-value="0">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
|
||||
<version name="version" column="version" type="int"/>
|
||||
|
||||
<property name="name"
|
||||
not-null="true"
|
||||
length="80"/>
|
||||
<property name="sex"
|
||||
not-null="true"
|
||||
update="false"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54E0"
|
||||
write="? * 2.54E0"/>
|
||||
</property>
|
||||
|
||||
<component name="address">
|
||||
<property name="address"/>
|
||||
<property name="zip"/>
|
||||
<property name="country"/>
|
||||
</component>
|
||||
|
||||
<joined-subclass name="Employee" table="JEmployee">
|
||||
<key column="person_id"/>
|
||||
<property name="title" column="`title`"
|
||||
not-null="true"
|
||||
length="20"/>
|
||||
<property name="salary"
|
||||
length="0"/>
|
||||
<property name="passwordExpiryDays">
|
||||
<column name="pwd_expiry_weeks"
|
||||
not-null="true"
|
||||
read="pwd_expiry_weeks * 7.0E0"
|
||||
write="? / 7.0E0"/>
|
||||
</property>
|
||||
<many-to-one name="manager"/>
|
||||
</joined-subclass>
|
||||
|
||||
<joined-subclass name="Customer" table="JManager">
|
||||
<key column="person_id"/>
|
||||
<property name="comments"/>
|
||||
<many-to-one name="salesperson"/>
|
||||
</joined-subclass>
|
||||
|
||||
</class>
|
||||
|
||||
|
||||
</hibernate-mapping>
|
100
hibernate-core/src/test/java/org/hibernate/orm/test/joinedsubclass/Person.java
Executable file
100
hibernate-core/src/test/java/org/hibernate/orm/test/joinedsubclass/Person.java
Executable file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* 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>.
|
||||
*/
|
||||
|
||||
//$Id: Person.java 10218 2006-08-04 18:24:04Z steve.ebersole@jboss.com $
|
||||
package org.hibernate.orm.test.joinedsubclass;
|
||||
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class Person {
|
||||
private long id;
|
||||
private String name;
|
||||
private char sex;
|
||||
private int version;
|
||||
private double heightInches;
|
||||
private Address address = new Address();
|
||||
/**
|
||||
* @return Returns the address.
|
||||
*/
|
||||
public Address getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public void setAddress(String string) {
|
||||
this.address.address = string;
|
||||
}
|
||||
|
||||
public void setZip(String string) {
|
||||
this.address.zip = string;
|
||||
}
|
||||
|
||||
public void setCountry(String string) {
|
||||
this.address.country = string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Returns the sex.
|
||||
*/
|
||||
public char getSex() {
|
||||
return sex;
|
||||
}
|
||||
/**
|
||||
* @param sex The sex to set.
|
||||
*/
|
||||
public void setSex(char sex) {
|
||||
this.sex = sex;
|
||||
}
|
||||
/**
|
||||
* @return Returns the id.
|
||||
*/
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id The id to set.
|
||||
*/
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @return Returns the identity.
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* @param identity The identity to set.
|
||||
*/
|
||||
public void setName(String identity) {
|
||||
this.name = identity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns the height in inches.
|
||||
*/
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param heightInches The height in inches to set.
|
||||
*/
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
|
||||
public int getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(int version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
@ -6,44 +6,49 @@
|
||||
*/
|
||||
package org.hibernate.test.joinedsubclass;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
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.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class JoinedSubclassTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
public String[] getMappings() {
|
||||
return new String[] { "joinedsubclass/Person.hbm.xml" };
|
||||
@DomainModel(
|
||||
xmlMappings = "org/hibernate/test/joinedsubclass/Person.hbm.xml"
|
||||
)
|
||||
@SessionFactory
|
||||
// few of the tests belonging to JoinedSubclassTest were already moved to org/hibernate/orm/test folder
|
||||
public class JoinedSubclassTest {
|
||||
|
||||
@AfterEach
|
||||
public void tearDown(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete from Employee" ).executeUpdate();
|
||||
session.createQuery( "delete from Customer" ).executeUpdate();
|
||||
session.createQuery( "delete from Person" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinedSubclass() {
|
||||
inTransaction( s -> {
|
||||
public void testJoinedSubclass(SessionFactoryScope scope) {
|
||||
scope.inTransaction( s -> {
|
||||
|
||||
Employee mark = new Employee();
|
||||
mark.setName( "Mark" );
|
||||
@ -134,145 +139,75 @@ public void testJoinedSubclass() {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAccessAsIncorrectSubclass() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
Employee e = new Employee();
|
||||
e.setName( "Steve" );
|
||||
e.setSex( 'M' );
|
||||
e.setTitle( "grand poobah" );
|
||||
s.save( e );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
public void testCustomColumnReadAndWrite(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
final double HEIGHT_INCHES = 73;
|
||||
final double HEIGHT_CENTIMETERS = HEIGHT_INCHES * 2.54d;
|
||||
Person p = new Person();
|
||||
p.setName( "Emmanuel" );
|
||||
p.setSex( 'M' );
|
||||
p.setHeightInches( HEIGHT_INCHES );
|
||||
session.persist( p );
|
||||
final double PASSWORD_EXPIRY_WEEKS = 4;
|
||||
final double PASSWORD_EXPIRY_DAYS = PASSWORD_EXPIRY_WEEKS * 7d;
|
||||
Employee e = new Employee();
|
||||
e.setName( "Steve" );
|
||||
e.setSex( 'M' );
|
||||
e.setTitle( "Mr" );
|
||||
e.setPasswordExpiryDays( PASSWORD_EXPIRY_DAYS );
|
||||
session.persist( e );
|
||||
session.flush();
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
Customer c = s.get( Customer.class, new Long( e.getId() ) );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
assertNull( c );
|
||||
// Test value conversion during insert
|
||||
// Value returned by Oracle native query is a Types.NUMERIC, which is mapped to a BigDecimalType;
|
||||
// Cast returned value to Number then call Number.doubleValue() so it works on all dialects.
|
||||
Double heightViaSql =
|
||||
( (Number) session.createNativeQuery(
|
||||
"select height_centimeters from JPerson where name='Emmanuel'" )
|
||||
.uniqueResult() )
|
||||
.doubleValue();
|
||||
assertEquals( HEIGHT_CENTIMETERS, heightViaSql, 0.01d );
|
||||
Double expiryViaSql =
|
||||
( (Number) session.createNativeQuery(
|
||||
"select pwd_expiry_weeks from JEmployee where person_id=?" )
|
||||
.setParameter( 1, e.getId() )
|
||||
.uniqueResult()
|
||||
).doubleValue();
|
||||
assertEquals( PASSWORD_EXPIRY_WEEKS, expiryViaSql, 0.01d );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
e = s.get( Employee.class, new Long( e.getId() ) );
|
||||
c = s.get( Customer.class, new Long( e.getId() ) );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
assertNotNull( e );
|
||||
assertNull( c );
|
||||
// Test projection
|
||||
Double heightViaHql = (Double) session.createQuery(
|
||||
"select p.heightInches from Person p where p.name = 'Emmanuel'" )
|
||||
.uniqueResult();
|
||||
assertEquals( HEIGHT_INCHES, heightViaHql, 0.01d );
|
||||
Double expiryViaHql = (Double) session.createQuery(
|
||||
"select e.passwordExpiryDays from Employee e where e.name = 'Steve'" ).uniqueResult();
|
||||
assertEquals( PASSWORD_EXPIRY_DAYS, expiryViaHql, 0.01d );
|
||||
|
||||
s = openSession();
|
||||
s.beginTransaction();
|
||||
s.delete( e );
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQuerySubclassAttribute() {
|
||||
inTransaction( s -> {
|
||||
Person p = new Person();
|
||||
p.setName( "Emmanuel" );
|
||||
p.setSex( 'M' );
|
||||
s.persist( p );
|
||||
Employee q = new Employee();
|
||||
q.setName( "Steve" );
|
||||
q.setSex( 'M' );
|
||||
q.setTitle( "Mr" );
|
||||
q.setSalary( new BigDecimal( 1000 ) );
|
||||
s.persist( q );
|
||||
|
||||
List result = s.createQuery( "from Person where salary > 100" ).list();
|
||||
assertEquals( result.size(), 1 );
|
||||
assertSame( result.get( 0 ), q );
|
||||
|
||||
result = s.createQuery( "from Person where salary > 100 or name like 'E%'" ).list();
|
||||
assertEquals( result.size(), 2 );
|
||||
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
|
||||
criteria.where( criteriaBuilder.gt(root.get( "salary" ), new BigDecimal( 100 ) ));
|
||||
|
||||
result = s.createQuery( criteria ).list();
|
||||
// result = s.createCriteria( Person.class )
|
||||
// .add( Property.forName( "salary" ).gt( new BigDecimal( 100 ) ) )
|
||||
// .list();
|
||||
assertEquals( result.size(), 1 );
|
||||
assertSame( result.get( 0 ), q );
|
||||
|
||||
//TODO: make this work:
|
||||
/*result = s.createQuery("select salary from Person where salary > 100").list();
|
||||
assertEquals( result.size(), 1 );
|
||||
assertEquals( result.get(0), new BigDecimal(1000) );*/
|
||||
|
||||
s.delete( p );
|
||||
s.delete( q );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
final double HEIGHT_INCHES = 73;
|
||||
final double HEIGHT_CENTIMETERS = HEIGHT_INCHES * 2.54d;
|
||||
Person p = new Person();
|
||||
p.setName( "Emmanuel" );
|
||||
p.setSex( 'M' );
|
||||
p.setHeightInches( HEIGHT_INCHES );
|
||||
s.persist( p );
|
||||
final double PASSWORD_EXPIRY_WEEKS = 4;
|
||||
final double PASSWORD_EXPIRY_DAYS = PASSWORD_EXPIRY_WEEKS * 7d;
|
||||
Employee e = new Employee();
|
||||
e.setName( "Steve" );
|
||||
e.setSex( 'M' );
|
||||
e.setTitle( "Mr" );
|
||||
e.setPasswordExpiryDays( PASSWORD_EXPIRY_DAYS );
|
||||
s.persist( e );
|
||||
s.flush();
|
||||
|
||||
// Test value conversion during insert
|
||||
// Value returned by Oracle native query is a Types.NUMERIC, which is mapped to a BigDecimalType;
|
||||
// Cast returned value to Number then call Number.doubleValue() so it works on all dialects.
|
||||
Double heightViaSql =
|
||||
( (Number) s.createNativeQuery( "select height_centimeters from JPerson where name='Emmanuel'" )
|
||||
.uniqueResult() )
|
||||
.doubleValue();
|
||||
assertEquals( HEIGHT_CENTIMETERS, heightViaSql, 0.01d );
|
||||
Double expiryViaSql =
|
||||
( (Number) s.createNativeQuery( "select pwd_expiry_weeks from JEmployee where person_id=?" )
|
||||
.setParameter( 1, e.getId() )
|
||||
.uniqueResult()
|
||||
).doubleValue();
|
||||
assertEquals( PASSWORD_EXPIRY_WEEKS, expiryViaSql, 0.01d );
|
||||
|
||||
// Test projection
|
||||
Double heightViaHql = (Double) s.createQuery( "select p.heightInches from Person p where p.name = 'Emmanuel'" )
|
||||
.uniqueResult();
|
||||
assertEquals( HEIGHT_INCHES, heightViaHql, 0.01d );
|
||||
Double expiryViaHql = (Double) s.createQuery(
|
||||
"select e.passwordExpiryDays from Employee e where e.name = 'Steve'" ).uniqueResult();
|
||||
assertEquals( PASSWORD_EXPIRY_DAYS, expiryViaHql, 0.01d );
|
||||
|
||||
// Test restriction and entity load via criteria
|
||||
// Test restriction and entity load via criteria
|
||||
// p = (Person)s.createCriteria(Person.class)
|
||||
// .add(Restrictions.between("heightInches", HEIGHT_INCHES - 0.01d, HEIGHT_INCHES + 0.01d))
|
||||
// .uniqueResult();
|
||||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
criteria.where( criteriaBuilder.between( root.get("heightInches"),HEIGHT_INCHES - 0.01d, HEIGHT_INCHES + 0.01d ) ) ;
|
||||
p = s.createQuery( criteria).uniqueResult();
|
||||
CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
criteria.where( criteriaBuilder.between(
|
||||
root.get( "heightInches" ),
|
||||
HEIGHT_INCHES - 0.01d,
|
||||
HEIGHT_INCHES + 0.01d
|
||||
) );
|
||||
p = session.createQuery( criteria ).uniqueResult();
|
||||
|
||||
assertEquals( HEIGHT_INCHES, p.getHeightInches(), 0.01d );
|
||||
CriteriaQuery<Employee> employeeCriteriaQuery = criteriaBuilder.createQuery( Employee.class );
|
||||
Root<Employee> employeeRoot = employeeCriteriaQuery.from( Employee.class );
|
||||
employeeCriteriaQuery.where( criteriaBuilder.between( employeeRoot.get("passwordExpiryDays"), PASSWORD_EXPIRY_DAYS - 0.01d,
|
||||
PASSWORD_EXPIRY_DAYS + 0.01d ) );
|
||||
e = s.createQuery( employeeCriteriaQuery ).uniqueResult();
|
||||
assertEquals( HEIGHT_INCHES, p.getHeightInches(), 0.01d );
|
||||
CriteriaQuery<Employee> employeeCriteriaQuery = criteriaBuilder.createQuery( Employee.class );
|
||||
Root<Employee> employeeRoot = employeeCriteriaQuery.from( Employee.class );
|
||||
employeeCriteriaQuery.where( criteriaBuilder.between(
|
||||
employeeRoot.get( "passwordExpiryDays" ),
|
||||
PASSWORD_EXPIRY_DAYS - 0.01d,
|
||||
PASSWORD_EXPIRY_DAYS + 0.01d
|
||||
) );
|
||||
e = session.createQuery( employeeCriteriaQuery ).uniqueResult();
|
||||
// e = (Employee) s.createCriteria( Employee.class )
|
||||
// .add( Restrictions.between(
|
||||
// "passwordExpiryDays",
|
||||
@ -280,67 +215,41 @@ public void testCustomColumnReadAndWrite() {
|
||||
// PASSWORD_EXPIRY_DAYS + 0.01d
|
||||
// ) )
|
||||
// .uniqueResult();
|
||||
assertEquals( PASSWORD_EXPIRY_DAYS, e.getPasswordExpiryDays(), 0.01d );
|
||||
assertEquals( PASSWORD_EXPIRY_DAYS, e.getPasswordExpiryDays(), 0.01d );
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
p = (Person) s.createQuery( "from Person p where p.heightInches between ?1 and ?2" )
|
||||
.setParameter( 1, HEIGHT_INCHES - 0.01d )
|
||||
.setParameter( 2, HEIGHT_INCHES + 0.01d )
|
||||
.uniqueResult();
|
||||
assertEquals( HEIGHT_INCHES, p.getHeightInches(), 0.01d );
|
||||
e = (Employee) s.createQuery( "from Employee e where e.passwordExpiryDays between ?1 and ?2" )
|
||||
.setParameter( 1, PASSWORD_EXPIRY_DAYS - 0.01d )
|
||||
.setParameter( 2, PASSWORD_EXPIRY_DAYS + 0.01d )
|
||||
.uniqueResult();
|
||||
assertEquals( PASSWORD_EXPIRY_DAYS, e.getPasswordExpiryDays(), 0.01d );
|
||||
// Test predicate and entity load via HQL
|
||||
p = (Person) session.createQuery( "from Person p where p.heightInches between ?1 and ?2" )
|
||||
.setParameter( 1, HEIGHT_INCHES - 0.01d )
|
||||
.setParameter( 2, HEIGHT_INCHES + 0.01d )
|
||||
.uniqueResult();
|
||||
assertEquals( HEIGHT_INCHES, p.getHeightInches(), 0.01d );
|
||||
e = (Employee) session.createQuery( "from Employee e where e.passwordExpiryDays between ?1 and ?2" )
|
||||
.setParameter( 1, PASSWORD_EXPIRY_DAYS - 0.01d )
|
||||
.setParameter( 2, PASSWORD_EXPIRY_DAYS + 0.01d )
|
||||
.uniqueResult();
|
||||
assertEquals( PASSWORD_EXPIRY_DAYS, e.getPasswordExpiryDays(), 0.01d );
|
||||
|
||||
// Test update
|
||||
p.setHeightInches( 1 );
|
||||
e.setPasswordExpiryDays( 7 );
|
||||
s.flush();
|
||||
heightViaSql =
|
||||
( (Number) s.createNativeQuery( "select height_centimeters from JPerson where name='Emmanuel'" )
|
||||
.uniqueResult() )
|
||||
.doubleValue();
|
||||
assertEquals( 2.54d, heightViaSql, 0.01d );
|
||||
expiryViaSql =
|
||||
( (Number) s.createNativeQuery( "select pwd_expiry_weeks from JEmployee where person_id=?" )
|
||||
.setParameter( 1, e.getId() )
|
||||
.uniqueResult()
|
||||
).doubleValue();
|
||||
assertEquals( 1d, expiryViaSql, 0.01d );
|
||||
s.delete( p );
|
||||
s.delete( e );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLockingJoinedSubclass() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Person p = new Person();
|
||||
p.setName( "Emmanuel" );
|
||||
p.setSex( 'M' );
|
||||
s.persist( p );
|
||||
Employee q = new Employee();
|
||||
q.setName( "Steve" );
|
||||
q.setSex( 'M' );
|
||||
q.setTitle( "Mr" );
|
||||
q.setSalary( new BigDecimal( 1000 ) );
|
||||
s.persist( q );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
s.lock( p, LockMode.UPGRADE );
|
||||
s.lock( q, LockMode.UPGRADE );
|
||||
s.delete( p );
|
||||
s.delete( q );
|
||||
t.commit();
|
||||
s.close();
|
||||
// Test update
|
||||
p.setHeightInches( 1 );
|
||||
e.setPasswordExpiryDays( 7 );
|
||||
session.flush();
|
||||
heightViaSql =
|
||||
( (Number) session.createNativeQuery(
|
||||
"select height_centimeters from JPerson where name='Emmanuel'" )
|
||||
.uniqueResult() )
|
||||
.doubleValue();
|
||||
assertEquals( 2.54d, heightViaSql, 0.01d );
|
||||
expiryViaSql =
|
||||
( (Number) session.createNativeQuery(
|
||||
"select pwd_expiry_weeks from JEmployee where person_id=?" )
|
||||
.setParameter( 1, e.getId() )
|
||||
.uniqueResult()
|
||||
).doubleValue();
|
||||
assertEquals( 1d, expiryViaSql, 0.01d );
|
||||
session.delete( p );
|
||||
session.delete( e );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user