Inhetirance : Fix stack overflow for Queryable#findSubPart and wrong value for Lockable#getRootTableName()

This commit is contained in:
Andrea Boriero 2020-07-20 15:49:25 +01:00
parent ba830d5ad5
commit 25fc3e2dce
13 changed files with 675 additions and 223 deletions

View File

@ -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.

View File

@ -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 ) {

View File

@ -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);

View File

@ -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;

View File

@ -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,

View File

@ -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 );

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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 );
}
);
}
}

View File

@ -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>

View 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;
}
}

View File

@ -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 );
}
);
}
}