HHH-4440 : column-level read/write fragment support
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@17821 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
d14de01220
commit
cb34e79283
|
@ -25,15 +25,12 @@
|
|||
package org.hibernate.cfg;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Properties;
|
||||
import java.util.StringTokenizer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.dom4j.Attribute;
|
||||
import org.dom4j.Document;
|
||||
import org.dom4j.Element;
|
||||
|
@ -42,10 +39,10 @@ import org.hibernate.EntityMode;
|
|||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.FilterDefinition;
|
||||
import org.hibernate.engine.NamedQueryDefinition;
|
||||
import org.hibernate.engine.Versioning;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||
import org.hibernate.mapping.Any;
|
||||
import org.hibernate.mapping.Array;
|
||||
|
@ -100,6 +97,8 @@ import org.hibernate.type.TypeFactory;
|
|||
import org.hibernate.util.JoinedIterator;
|
||||
import org.hibernate.util.ReflectHelper;
|
||||
import org.hibernate.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Walks an XML mapping document and produces the Hibernate configuration-time metamodel (the
|
||||
|
@ -1705,7 +1704,7 @@ public final class HbmBinder {
|
|||
|
||||
}
|
||||
|
||||
public static void bindColumn(Element node, Column column, boolean isNullable) {
|
||||
public static void bindColumn(Element node, Column column, boolean isNullable) throws MappingException {
|
||||
Attribute lengthNode = node.attribute( "length" );
|
||||
if ( lengthNode != null ) column.setLength( Integer.parseInt( lengthNode.getValue() ) );
|
||||
Attribute scalNode = node.attribute( "scale" );
|
||||
|
@ -1725,6 +1724,13 @@ public final class HbmBinder {
|
|||
Attribute typeNode = node.attribute( "sql-type" );
|
||||
if ( typeNode != null ) column.setSqlType( typeNode.getValue() );
|
||||
|
||||
String customWrite = node.attributeValue( "write" );
|
||||
if(customWrite != null && !customWrite.matches("[^?]*\\?[^?]*")) {
|
||||
throw new MappingException("write expression must contain exactly one value placeholder ('?') character");
|
||||
}
|
||||
column.setCustomWrite( customWrite );
|
||||
column.setCustomRead( node.attributeValue( "read" ) );
|
||||
|
||||
Element comment = node.element("comment");
|
||||
if (comment!=null) column.setComment( comment.getTextTrim() );
|
||||
|
||||
|
|
|
@ -24,23 +24,23 @@
|
|||
*/
|
||||
package org.hibernate.dialect.lock;
|
||||
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.exception.JDBCExceptionHelper;
|
||||
import org.hibernate.sql.Update;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.JDBCException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.exception.JDBCExceptionHelper;
|
||||
import org.hibernate.persister.entity.Lockable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.sql.Update;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* A locking strategy where the locks are obtained through update statements.
|
||||
* <p/>
|
||||
|
@ -131,7 +131,7 @@ public class UpdateLockingStrategy implements LockingStrategy {
|
|||
SessionFactoryImplementor factory = lockable.getFactory();
|
||||
Update update = new Update( factory.getDialect() );
|
||||
update.setTableName( lockable.getRootTableName() );
|
||||
update.setPrimaryKeyColumnNames( lockable.getRootTableIdentifierColumnNames() );
|
||||
update.addPrimaryKeyColumns( lockable.getRootTableIdentifierColumnNames() );
|
||||
update.setVersionColumnName( lockable.getVersionColumnName() );
|
||||
update.addColumn( lockable.getVersionColumnName() );
|
||||
if ( factory.getSettings().isCommentsEnabled() ) {
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.MappingException;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.function.SQLFunctionRegistry;
|
||||
import org.hibernate.engine.Mapping;
|
||||
import org.hibernate.sql.Template;
|
||||
import org.hibernate.util.StringHelper;
|
||||
|
||||
/**
|
||||
|
@ -58,6 +59,8 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
private String checkConstraint;
|
||||
private String comment;
|
||||
private String defaultValue;
|
||||
private String customWrite;
|
||||
private String customRead;
|
||||
|
||||
public Column() { };
|
||||
|
||||
|
@ -260,9 +263,18 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
}
|
||||
|
||||
public String getTemplate(Dialect dialect, SQLFunctionRegistry functionRegistry) {
|
||||
return getQuotedName(dialect);
|
||||
String expr = getReadExpr(dialect);
|
||||
return Template.renderWhereStringTemplate(expr, dialect, functionRegistry);
|
||||
}
|
||||
|
||||
public String getReadExpr(Dialect dialect) {
|
||||
return ( customRead != null && customRead.length() > 0 ) ? customRead : getQuotedName(dialect);
|
||||
}
|
||||
|
||||
public String getWriteExpr() {
|
||||
return ( customWrite != null && customWrite.length() > 0 ) ? customWrite : "?";
|
||||
}
|
||||
|
||||
public boolean isFormula() {
|
||||
return false;
|
||||
}
|
||||
|
@ -304,6 +316,22 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
public String getCustomWrite() {
|
||||
return customWrite;
|
||||
}
|
||||
|
||||
public void setCustomWrite(String customWrite) {
|
||||
this.customWrite = customWrite;
|
||||
}
|
||||
|
||||
public String getCustomRead() {
|
||||
return customRead;
|
||||
}
|
||||
|
||||
public void setCustomRead(String customRead) {
|
||||
this.customRead = customRead;
|
||||
}
|
||||
|
||||
public String getCanonicalName() {
|
||||
return quoted ? name : name.toLowerCase();
|
||||
}
|
||||
|
@ -327,6 +355,8 @@ public class Column implements Selectable, Serializable, Cloneable {
|
|||
copy.setCheckConstraint( checkConstraint );
|
||||
copy.setComment( comment );
|
||||
copy.setDefaultValue( defaultValue );
|
||||
copy.setCustomRead( customRead );
|
||||
copy.setCustomWrite( customWrite );
|
||||
return copy;
|
||||
}
|
||||
|
||||
|
|
|
@ -33,16 +33,12 @@ import java.util.HashMap;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cache.entry.CacheEntryStructure;
|
||||
|
@ -53,15 +49,17 @@ import org.hibernate.cfg.Configuration;
|
|||
import org.hibernate.collection.PersistentCollection;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.EntityKey;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.PersistenceContext;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.SubselectFetch;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.LoadQueryInfluencers;
|
||||
import org.hibernate.exception.JDBCExceptionHelper;
|
||||
import org.hibernate.exception.SQLExceptionConverter;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.loader.collection.CollectionInitializer;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.mapping.Column;
|
||||
|
@ -88,6 +86,8 @@ import org.hibernate.type.Type;
|
|||
import org.hibernate.util.ArrayHelper;
|
||||
import org.hibernate.util.FilterHelper;
|
||||
import org.hibernate.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
|
@ -140,6 +140,9 @@ public abstract class AbstractCollectionPersister
|
|||
protected final String[] indexFormulas;
|
||||
protected final boolean[] indexColumnIsSettable;
|
||||
protected final String[] elementColumnNames;
|
||||
protected final String[] elementColumnWriters;
|
||||
protected final String[] elementColumnReaders;
|
||||
protected final String[] elementColumnReaderTemplates;
|
||||
protected final String[] elementFormulaTemplates;
|
||||
protected final String[] elementFormulas;
|
||||
protected final boolean[] elementColumnIsSettable;
|
||||
|
@ -320,6 +323,9 @@ public abstract class AbstractCollectionPersister
|
|||
int elementSpan = collection.getElement().getColumnSpan();
|
||||
elementColumnAliases = new String[elementSpan];
|
||||
elementColumnNames = new String[elementSpan];
|
||||
elementColumnWriters = new String[elementSpan];
|
||||
elementColumnReaders = new String[elementSpan];
|
||||
elementColumnReaderTemplates = new String[elementSpan];
|
||||
elementFormulaTemplates = new String[elementSpan];
|
||||
elementFormulas = new String[elementSpan];
|
||||
elementColumnIsSettable = new boolean[elementSpan];
|
||||
|
@ -339,6 +345,9 @@ public abstract class AbstractCollectionPersister
|
|||
else {
|
||||
Column col = (Column) selectable;
|
||||
elementColumnNames[j] = col.getQuotedName(dialect);
|
||||
elementColumnWriters[j] = col.getWriteExpr();
|
||||
elementColumnReaders[j] = col.getReadExpr(dialect);
|
||||
elementColumnReaderTemplates[j] = col.getTemplate(dialect, factory.getSqlFunctionRegistry());
|
||||
elementColumnIsSettable[j] = true;
|
||||
elementColumnIsInPrimaryKey[j] = !col.isNullable();
|
||||
if ( !col.isNullable() ) {
|
||||
|
@ -513,6 +522,8 @@ public abstract class AbstractCollectionPersister
|
|||
if ( elementType.isComponentType() ) {
|
||||
elementPropertyMapping = new CompositeElementPropertyMapping(
|
||||
elementColumnNames,
|
||||
elementColumnReaders,
|
||||
elementColumnReaderTemplates,
|
||||
elementFormulaTemplates,
|
||||
(AbstractComponentType) elementType,
|
||||
factory
|
||||
|
@ -970,7 +981,7 @@ public abstract class AbstractCollectionPersister
|
|||
protected void appendElementColumns(SelectFragment frag, String elemAlias) {
|
||||
for ( int i=0; i<elementColumnIsSettable.length; i++ ) {
|
||||
if ( elementColumnIsSettable[i] ) {
|
||||
frag.addColumn( elemAlias, elementColumnNames[i], elementColumnAliases[i] );
|
||||
frag.addColumnTemplate( elemAlias, elementColumnReaderTemplates[i], elementColumnAliases[i] );
|
||||
}
|
||||
else {
|
||||
frag.addFormula( elemAlias, elementFormulaTemplates[i], elementColumnAliases[i] );
|
||||
|
|
|
@ -31,10 +31,6 @@ import java.util.Iterator;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
@ -44,15 +40,19 @@ import org.hibernate.engine.SessionImplementor;
|
|||
import org.hibernate.engine.SubselectFetch;
|
||||
import org.hibernate.engine.LoadQueryInfluencers;
|
||||
import org.hibernate.exception.JDBCExceptionHelper;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.loader.collection.BatchingCollectionInitializer;
|
||||
import org.hibernate.loader.collection.CollectionInitializer;
|
||||
import org.hibernate.loader.collection.SubselectCollectionLoader;
|
||||
import org.hibernate.mapping.Collection;
|
||||
import org.hibernate.persister.entity.Joinable;
|
||||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.sql.Delete;
|
||||
import org.hibernate.sql.Insert;
|
||||
import org.hibernate.sql.Update;
|
||||
import org.hibernate.sql.SelectFragment;
|
||||
import org.hibernate.sql.Update;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.util.ArrayHelper;
|
||||
|
||||
/**
|
||||
|
@ -81,7 +81,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
|
|||
|
||||
Delete delete = new Delete()
|
||||
.setTableName( qualifiedTableName )
|
||||
.setPrimaryKeyColumnNames( keyColumnNames );
|
||||
.addPrimaryKeyColumns( keyColumnNames );
|
||||
|
||||
if ( hasWhere ) delete.setWhere( sqlWhereString );
|
||||
|
||||
|
@ -112,7 +112,7 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
|
|||
}
|
||||
|
||||
//if ( !elementIsFormula ) {
|
||||
insert.addColumns( elementColumnNames, elementColumnIsSettable );
|
||||
insert.addColumns( elementColumnNames, elementColumnIsSettable, elementColumnWriters );
|
||||
//}
|
||||
|
||||
return insert.toStatementString();
|
||||
|
@ -127,17 +127,18 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
|
|||
.setTableName( qualifiedTableName );
|
||||
|
||||
//if ( !elementIsFormula ) {
|
||||
update.addColumns( elementColumnNames, elementColumnIsSettable );
|
||||
update.addColumns( elementColumnNames, elementColumnIsSettable, elementColumnWriters );
|
||||
//}
|
||||
|
||||
if ( hasIdentifier ) {
|
||||
update.setPrimaryKeyColumnNames( new String[]{ identifierColumnName } );
|
||||
update.addPrimaryKeyColumns( new String[]{ identifierColumnName } );
|
||||
}
|
||||
else if ( hasIndex && !indexContainsFormula ) {
|
||||
update.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, indexColumnNames ) );
|
||||
update.addPrimaryKeyColumns( ArrayHelper.join( keyColumnNames, indexColumnNames ) );
|
||||
}
|
||||
else {
|
||||
update.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, elementColumnNames, elementColumnIsInPrimaryKey ) );
|
||||
update.addPrimaryKeyColumns( keyColumnNames );
|
||||
update.addPrimaryKeyColumns( elementColumnNames, elementColumnIsInPrimaryKey, elementColumnWriters );
|
||||
}
|
||||
|
||||
if ( getFactory().getSettings().isCommentsEnabled() ) {
|
||||
|
@ -156,13 +157,14 @@ public class BasicCollectionPersister extends AbstractCollectionPersister {
|
|||
.setTableName( qualifiedTableName );
|
||||
|
||||
if ( hasIdentifier ) {
|
||||
delete.setPrimaryKeyColumnNames( new String[]{ identifierColumnName } );
|
||||
delete.addPrimaryKeyColumns( new String[]{ identifierColumnName } );
|
||||
}
|
||||
else if ( hasIndex && !indexContainsFormula ) {
|
||||
delete.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, indexColumnNames ) );
|
||||
delete.addPrimaryKeyColumns( ArrayHelper.join( keyColumnNames, indexColumnNames ) );
|
||||
}
|
||||
else {
|
||||
delete.setPrimaryKeyColumnNames( ArrayHelper.join( keyColumnNames, elementColumnNames, elementColumnIsInPrimaryKey ) );
|
||||
delete.addPrimaryKeyColumns( keyColumnNames );
|
||||
delete.addPrimaryKeyColumns( elementColumnNames, elementColumnIsInPrimaryKey, elementColumnWriters );
|
||||
}
|
||||
|
||||
if ( getFactory().getSettings().isCommentsEnabled() ) {
|
||||
|
|
|
@ -38,7 +38,9 @@ public class CompositeElementPropertyMapping extends AbstractPropertyMapping {
|
|||
private final AbstractComponentType compositeType;
|
||||
|
||||
public CompositeElementPropertyMapping(
|
||||
String[] elementColumns,
|
||||
String[] elementColumns,
|
||||
String[] elementColumnReaders,
|
||||
String[] elementColumnReaderTemplates,
|
||||
String[] elementFormulaTemplates,
|
||||
AbstractComponentType compositeType,
|
||||
Mapping factory)
|
||||
|
@ -46,7 +48,8 @@ public class CompositeElementPropertyMapping extends AbstractPropertyMapping {
|
|||
|
||||
this.compositeType = compositeType;
|
||||
|
||||
initComponentPropertyPaths(null, compositeType, elementColumns, elementFormulaTemplates, factory);
|
||||
initComponentPropertyPaths(null, compositeType, elementColumns, elementColumnReaders,
|
||||
elementColumnReaderTemplates, elementFormulaTemplates, factory);
|
||||
|
||||
}
|
||||
|
||||
|
@ -58,4 +61,4 @@ public class CompositeElementPropertyMapping extends AbstractPropertyMapping {
|
|||
return compositeType.getName();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,8 +31,6 @@ import java.util.Iterator;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.access.CollectionRegionAccessStrategy;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
|
@ -42,6 +40,8 @@ import org.hibernate.engine.SessionImplementor;
|
|||
import org.hibernate.engine.SubselectFetch;
|
||||
import org.hibernate.engine.LoadQueryInfluencers;
|
||||
import org.hibernate.exception.JDBCExceptionHelper;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.loader.collection.BatchingCollectionInitializer;
|
||||
import org.hibernate.loader.collection.CollectionInitializer;
|
||||
import org.hibernate.loader.collection.SubselectOneToManyLoader;
|
||||
|
@ -96,7 +96,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
|
|||
Update update = new Update( getDialect() )
|
||||
.setTableName( qualifiedTableName )
|
||||
.addColumns( keyColumnNames, "null" )
|
||||
.setPrimaryKeyColumnNames( keyColumnNames );
|
||||
.addPrimaryKeyColumns( keyColumnNames );
|
||||
|
||||
if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames, "null" );
|
||||
|
||||
|
@ -125,7 +125,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
|
|||
update.setComment( "create one-to-many row " + getRole() );
|
||||
}
|
||||
|
||||
return update.setPrimaryKeyColumnNames( elementColumnNames )
|
||||
return update.addPrimaryKeyColumns( elementColumnNames, elementColumnWriters )
|
||||
.toStatementString();
|
||||
}
|
||||
|
||||
|
@ -156,7 +156,7 @@ public class OneToManyPersister extends AbstractCollectionPersister {
|
|||
//the ordering of removal and addition is not guaranteed when
|
||||
//a child moves from one parent to another
|
||||
String[] rowSelectColumnNames = ArrayHelper.join(keyColumnNames, elementColumnNames);
|
||||
return update.setPrimaryKeyColumnNames( rowSelectColumnNames )
|
||||
return update.addPrimaryKeyColumns( rowSelectColumnNames )
|
||||
.toStatementString();
|
||||
}
|
||||
|
||||
|
|
|
@ -30,15 +30,13 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.Comparator;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.FetchMode;
|
||||
|
@ -48,36 +46,36 @@ import org.hibernate.MappingException;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
||||
import org.hibernate.dialect.lock.LockingStrategy;
|
||||
import org.hibernate.cache.CacheKey;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.cache.entry.CacheEntry;
|
||||
import org.hibernate.cache.entry.CacheEntryStructure;
|
||||
import org.hibernate.cache.entry.StructuredCacheEntry;
|
||||
import org.hibernate.cache.entry.UnstructuredCacheEntry;
|
||||
import org.hibernate.dialect.lock.LockingStrategy;
|
||||
import org.hibernate.engine.CascadeStyle;
|
||||
import org.hibernate.engine.CascadingAction;
|
||||
import org.hibernate.engine.EntityEntry;
|
||||
import org.hibernate.engine.EntityKey;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.Mapping;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.engine.Versioning;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.EntityKey;
|
||||
import org.hibernate.engine.ValueInclusion;
|
||||
import org.hibernate.engine.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.Versioning;
|
||||
import org.hibernate.exception.JDBCExceptionHelper;
|
||||
import org.hibernate.id.IdentifierGenerator;
|
||||
import org.hibernate.id.PostInsertIdentifierGenerator;
|
||||
import org.hibernate.id.PostInsertIdentityPersister;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.id.insert.Binder;
|
||||
import org.hibernate.intercept.LazyPropertyInitializer;
|
||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||
import org.hibernate.intercept.FieldInterceptionHelper;
|
||||
import org.hibernate.intercept.FieldInterceptor;
|
||||
import org.hibernate.intercept.LazyPropertyInitializer;
|
||||
import org.hibernate.jdbc.Expectation;
|
||||
import org.hibernate.jdbc.Expectations;
|
||||
import org.hibernate.jdbc.TooManyRowsAffectedException;
|
||||
import org.hibernate.loader.entity.BatchingEntityLoader;
|
||||
import org.hibernate.loader.entity.CascadeEntityLoader;
|
||||
import org.hibernate.loader.entity.EntityLoader;
|
||||
|
@ -99,10 +97,9 @@ import org.hibernate.sql.SelectFragment;
|
|||
import org.hibernate.sql.SimpleSelect;
|
||||
import org.hibernate.sql.Template;
|
||||
import org.hibernate.sql.Update;
|
||||
import org.hibernate.sql.AliasGenerator;
|
||||
import org.hibernate.tuple.Tuplizer;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.hibernate.tuple.entity.EntityTuplizer;
|
||||
import org.hibernate.tuple.Tuplizer;
|
||||
import org.hibernate.type.AbstractComponentType;
|
||||
import org.hibernate.type.AssociationType;
|
||||
import org.hibernate.type.EntityType;
|
||||
|
@ -112,6 +109,8 @@ import org.hibernate.type.VersionType;
|
|||
import org.hibernate.util.ArrayHelper;
|
||||
import org.hibernate.util.FilterHelper;
|
||||
import org.hibernate.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Basic functionality for persisting an entity via JDBC
|
||||
|
@ -136,6 +135,8 @@ public abstract class AbstractEntityPersister
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
private final String[] rootTableKeyColumnNames;
|
||||
private final String[] rootTableKeyColumnReaders;
|
||||
private final String[] rootTableKeyColumnReaderTemplates;
|
||||
private final String[] identifierAliases;
|
||||
private final int identifierColumnSpan;
|
||||
private final String versionColumnName;
|
||||
|
@ -158,6 +159,8 @@ public abstract class AbstractEntityPersister
|
|||
private final String[][] propertyColumnAliases;
|
||||
private final String[][] propertyColumnNames;
|
||||
private final String[][] propertyColumnFormulaTemplates;
|
||||
private final String[][] propertyColumnReaderTemplates;
|
||||
private final String[][] propertyColumnWriters;
|
||||
private final boolean[][] propertyColumnUpdateable;
|
||||
private final boolean[][] propertyColumnInsertable;
|
||||
private final boolean[] propertyUniqueness;
|
||||
|
@ -175,6 +178,8 @@ public abstract class AbstractEntityPersister
|
|||
private final Type[] subclassPropertyTypeClosure;
|
||||
private final String[][] subclassPropertyFormulaTemplateClosure;
|
||||
private final String[][] subclassPropertyColumnNameClosure;
|
||||
private final String[][] subclassPropertyColumnReaderClosure;
|
||||
private final String[][] subclassPropertyColumnReaderTemplateClosure;
|
||||
private final FetchMode[] subclassPropertyFetchModeClosure;
|
||||
private final boolean[] subclassPropertyNullabilityClosure;
|
||||
private final boolean[] propertyDefinedOnSubclass;
|
||||
|
@ -187,6 +192,7 @@ public abstract class AbstractEntityPersister
|
|||
private final boolean[] subclassColumnLazyClosure;
|
||||
private final String[] subclassColumnAliasClosure;
|
||||
private final boolean[] subclassColumnSelectableClosure;
|
||||
private final String[] subclassColumnReaderTemplateClosure;
|
||||
private final String[] subclassFormulaClosure;
|
||||
private final String[] subclassFormulaTemplateClosure;
|
||||
private final String[] subclassFormulaAliasClosure;
|
||||
|
@ -285,6 +291,14 @@ public abstract class AbstractEntityPersister
|
|||
return DISCRIMINATOR_ALIAS;
|
||||
}
|
||||
|
||||
public String getDiscriminatorColumnReaders() {
|
||||
return DISCRIMINATOR_ALIAS;
|
||||
}
|
||||
|
||||
public String getDiscriminatorColumnReaderTemplate() {
|
||||
return DISCRIMINATOR_ALIAS;
|
||||
}
|
||||
|
||||
protected String getDiscriminatorAlias() {
|
||||
return DISCRIMINATOR_ALIAS;
|
||||
}
|
||||
|
@ -471,6 +485,8 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
identifierColumnSpan = persistentClass.getIdentifier().getColumnSpan();
|
||||
rootTableKeyColumnNames = new String[identifierColumnSpan];
|
||||
rootTableKeyColumnReaders = new String[identifierColumnSpan];
|
||||
rootTableKeyColumnReaderTemplates = new String[identifierColumnSpan];
|
||||
identifierAliases = new String[identifierColumnSpan];
|
||||
|
||||
rowIdName = persistentClass.getRootTable().getRowId();
|
||||
|
@ -482,6 +498,8 @@ public abstract class AbstractEntityPersister
|
|||
while ( iter.hasNext() ) {
|
||||
Column col = ( Column ) iter.next();
|
||||
rootTableKeyColumnNames[i] = col.getQuotedName( factory.getDialect() );
|
||||
rootTableKeyColumnReaders[i] = col.getReadExpr( factory.getDialect() );
|
||||
rootTableKeyColumnReaderTemplates[i] = col.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
identifierAliases[i] = col.getAlias( factory.getDialect(), persistentClass.getRootTable() );
|
||||
i++;
|
||||
}
|
||||
|
@ -512,6 +530,8 @@ public abstract class AbstractEntityPersister
|
|||
propertyColumnAliases = new String[hydrateSpan][];
|
||||
propertyColumnNames = new String[hydrateSpan][];
|
||||
propertyColumnFormulaTemplates = new String[hydrateSpan][];
|
||||
propertyColumnReaderTemplates = new String[hydrateSpan][];
|
||||
propertyColumnWriters = new String[hydrateSpan][];
|
||||
propertyUniqueness = new boolean[hydrateSpan];
|
||||
propertySelectable = new boolean[hydrateSpan];
|
||||
propertyColumnUpdateable = new boolean[hydrateSpan][];
|
||||
|
@ -536,7 +556,9 @@ public abstract class AbstractEntityPersister
|
|||
propertySubclassNames[i] = prop.getPersistentClass().getEntityName();
|
||||
String[] colNames = new String[span];
|
||||
String[] colAliases = new String[span];
|
||||
String[] templates = new String[span];
|
||||
String[] colReaderTemplates = new String[span];
|
||||
String[] colWriters = new String[span];
|
||||
String[] formulaTemplates = new String[span];
|
||||
Iterator colIter = prop.getColumnIterator();
|
||||
int k = 0;
|
||||
while ( colIter.hasNext() ) {
|
||||
|
@ -544,15 +566,20 @@ public abstract class AbstractEntityPersister
|
|||
colAliases[k] = thing.getAlias( factory.getDialect() , prop.getValue().getTable() );
|
||||
if ( thing.isFormula() ) {
|
||||
foundFormula = true;
|
||||
templates[k] = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
formulaTemplates[k] = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
}
|
||||
else {
|
||||
colNames[k] = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
Column col = (Column)thing;
|
||||
colNames[k] = col.getQuotedName( factory.getDialect() );
|
||||
colReaderTemplates[k] = col.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
colWriters[k] = col.getWriteExpr();
|
||||
}
|
||||
k++;
|
||||
}
|
||||
propertyColumnNames[i] = colNames;
|
||||
propertyColumnFormulaTemplates[i] = templates;
|
||||
propertyColumnFormulaTemplates[i] = formulaTemplates;
|
||||
propertyColumnReaderTemplates[i] = colReaderTemplates;
|
||||
propertyColumnWriters[i] = colWriters;
|
||||
propertyColumnAliases[i] = colAliases;
|
||||
|
||||
if ( lazyAvailable && prop.isLazy() ) {
|
||||
|
@ -583,6 +610,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
ArrayList columns = new ArrayList();
|
||||
ArrayList columnsLazy = new ArrayList();
|
||||
ArrayList columnReaderTemplates = new ArrayList();
|
||||
ArrayList aliases = new ArrayList();
|
||||
ArrayList formulas = new ArrayList();
|
||||
ArrayList formulaAliases = new ArrayList();
|
||||
|
@ -593,6 +621,8 @@ public abstract class AbstractEntityPersister
|
|||
ArrayList classes = new ArrayList();
|
||||
ArrayList templates = new ArrayList();
|
||||
ArrayList propColumns = new ArrayList();
|
||||
ArrayList propColumnReaders = new ArrayList();
|
||||
ArrayList propColumnReaderTemplates = new ArrayList();
|
||||
ArrayList joinedFetchesList = new ArrayList();
|
||||
ArrayList cascades = new ArrayList();
|
||||
ArrayList definedBySubclass = new ArrayList();
|
||||
|
@ -613,6 +643,8 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
Iterator colIter = prop.getColumnIterator();
|
||||
String[] cols = new String[prop.getColumnSpan()];
|
||||
String[] readers = new String[prop.getColumnSpan()];
|
||||
String[] readerTemplates = new String[prop.getColumnSpan()];
|
||||
String[] forms = new String[prop.getColumnSpan()];
|
||||
int[] colnos = new int[prop.getColumnSpan()];
|
||||
int[] formnos = new int[prop.getColumnSpan()];
|
||||
|
@ -631,7 +663,8 @@ public abstract class AbstractEntityPersister
|
|||
formulasLazy.add( lazy );
|
||||
}
|
||||
else {
|
||||
String colName = thing.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
Column col = (Column)thing;
|
||||
String colName = col.getQuotedName( factory.getDialect() );
|
||||
colnos[l] = columns.size(); //before add :-)
|
||||
formnos[l] = -1;
|
||||
columns.add( colName );
|
||||
|
@ -639,10 +672,17 @@ public abstract class AbstractEntityPersister
|
|||
aliases.add( thing.getAlias( factory.getDialect(), prop.getValue().getTable() ) );
|
||||
columnsLazy.add( lazy );
|
||||
columnSelectables.add( Boolean.valueOf( prop.isSelectable() ) );
|
||||
|
||||
readers[l] = col.getReadExpr( factory.getDialect() );
|
||||
String readerTemplate = col.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
readerTemplates[l] = readerTemplate;
|
||||
columnReaderTemplates.add( readerTemplate );
|
||||
}
|
||||
l++;
|
||||
}
|
||||
propColumns.add( cols );
|
||||
propColumnReaders.add( readers );
|
||||
propColumnReaderTemplates.add( readerTemplates );
|
||||
templates.add( forms );
|
||||
propColumnNumbers.add( colnos );
|
||||
propFormulaNumbers.add( formnos );
|
||||
|
@ -654,6 +694,7 @@ public abstract class AbstractEntityPersister
|
|||
subclassColumnAliasClosure = ArrayHelper.toStringArray( aliases );
|
||||
subclassColumnLazyClosure = ArrayHelper.toBooleanArray( columnsLazy );
|
||||
subclassColumnSelectableClosure = ArrayHelper.toBooleanArray( columnSelectables );
|
||||
subclassColumnReaderTemplateClosure = ArrayHelper.toStringArray( columnReaderTemplates );
|
||||
|
||||
subclassFormulaClosure = ArrayHelper.toStringArray( formulas );
|
||||
subclassFormulaTemplateClosure = ArrayHelper.toStringArray( formulaTemplates );
|
||||
|
@ -666,6 +707,8 @@ public abstract class AbstractEntityPersister
|
|||
subclassPropertyNullabilityClosure = ArrayHelper.toBooleanArray( propNullables );
|
||||
subclassPropertyFormulaTemplateClosure = ArrayHelper.to2DStringArray( templates );
|
||||
subclassPropertyColumnNameClosure = ArrayHelper.to2DStringArray( propColumns );
|
||||
subclassPropertyColumnReaderClosure = ArrayHelper.to2DStringArray( propColumnReaders );
|
||||
subclassPropertyColumnReaderTemplateClosure = ArrayHelper.to2DStringArray( propColumnReaderTemplates );
|
||||
subclassPropertyColumnNumberClosure = ArrayHelper.to2DIntArray( propColumnNumbers );
|
||||
subclassPropertyFormulaNumberClosure = ArrayHelper.to2DIntArray( propFormulaNumbers );
|
||||
|
||||
|
@ -906,6 +949,14 @@ public abstract class AbstractEntityPersister
|
|||
return rootTableKeyColumnNames;
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaders() {
|
||||
return rootTableKeyColumnReaders;
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaderTemplates() {
|
||||
return rootTableKeyColumnReaderTemplates;
|
||||
}
|
||||
|
||||
protected int getIdentifierColumnSpan() {
|
||||
return identifierColumnSpan;
|
||||
}
|
||||
|
@ -997,14 +1048,14 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
|
||||
String[] columnAliases = getSubclassColumnAliasClosure();
|
||||
String[] columns = getSubclassColumnClosure();
|
||||
String[] columnReaderTemplates = getSubclassColumnReaderTemplateClosure();
|
||||
for ( int i = 0; i < getSubclassColumnClosure().length; i++ ) {
|
||||
boolean selectable = ( allProperties || !subclassColumnLazyClosure[i] ) &&
|
||||
!isSubclassTableSequentialSelect( columnTableNumbers[i] ) &&
|
||||
subclassColumnSelectableClosure[i];
|
||||
if ( selectable ) {
|
||||
String subalias = generateTableAlias( tableAlias, columnTableNumbers[i] );
|
||||
select.addColumn( subalias, columns[i], columnAliases[i] );
|
||||
select.addColumnTemplate( subalias, columnReaderTemplates[i], columnAliases[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1174,9 +1225,9 @@ public abstract class AbstractEntityPersister
|
|||
SelectFragment frag = new SelectFragment();
|
||||
for ( int i = 0; i < propertyCount; i++ ) {
|
||||
if ( inclusionChecker.includeProperty( i ) ) {
|
||||
frag.addColumns(
|
||||
frag.addColumnTemplates(
|
||||
generateTableAlias( alias, propertyTableNumbers[i] ),
|
||||
propertyColumnNames[i],
|
||||
propertyColumnReaderTemplates[i],
|
||||
propertyColumnAliases[i]
|
||||
);
|
||||
frag.addFormulas(
|
||||
|
@ -1284,7 +1335,7 @@ public abstract class AbstractEntityPersister
|
|||
update.setComment( "forced version increment" );
|
||||
}
|
||||
update.addColumn( getVersionColumnName() );
|
||||
update.setPrimaryKeyColumnNames( getIdentifierColumnNames() );
|
||||
update.addPrimaryKeyColumns( getIdentifierColumnNames() );
|
||||
update.setVersionColumnName( getVersionColumnName() );
|
||||
return update.toStatementString();
|
||||
}
|
||||
|
@ -1472,6 +1523,10 @@ public abstract class AbstractEntityPersister
|
|||
public String[] getPropertyColumnNames(int i) {
|
||||
return propertyColumnNames[i];
|
||||
}
|
||||
|
||||
public String[] getPropertyColumnWriters(int i) {
|
||||
return propertyColumnWriters[i];
|
||||
}
|
||||
|
||||
protected int getPropertyColumnSpan(int i) {
|
||||
return propertyColumnSpans[i];
|
||||
|
@ -1520,6 +1575,14 @@ public abstract class AbstractEntityPersister
|
|||
protected String[][] getSubclassPropertyColumnNameClosure() {
|
||||
return subclassPropertyColumnNameClosure;
|
||||
}
|
||||
|
||||
public String[][] getSubclassPropertyColumnReaderClosure() {
|
||||
return subclassPropertyColumnReaderClosure;
|
||||
}
|
||||
|
||||
public String[][] getSubclassPropertyColumnReaderTemplateClosure() {
|
||||
return subclassPropertyColumnReaderTemplateClosure;
|
||||
}
|
||||
|
||||
protected String[] getSubclassPropertyNameClosure() {
|
||||
return subclassPropertyNameClosure;
|
||||
|
@ -1537,6 +1600,10 @@ public abstract class AbstractEntityPersister
|
|||
return subclassColumnAliasClosure;
|
||||
}
|
||||
|
||||
public String[] getSubclassColumnReaderTemplateClosure() {
|
||||
return subclassColumnReaderTemplateClosure;
|
||||
}
|
||||
|
||||
protected String[] getSubclassFormulaClosure() {
|
||||
return subclassFormulaClosure;
|
||||
}
|
||||
|
@ -1744,6 +1811,8 @@ public abstract class AbstractEntityPersister
|
|||
propertyMapping.initPropertyPaths( getSubclassPropertyNameClosure()[i],
|
||||
getSubclassPropertyTypeClosure()[i],
|
||||
getSubclassPropertyColumnNameClosure()[i],
|
||||
getSubclassPropertyColumnReaderClosure()[i],
|
||||
getSubclassPropertyColumnReaderTemplateClosure()[i],
|
||||
getSubclassPropertyFormulaTemplateClosure()[i],
|
||||
mapping );
|
||||
}
|
||||
|
@ -1752,13 +1821,16 @@ public abstract class AbstractEntityPersister
|
|||
private void initIdentifierPropertyPaths(Mapping mapping) throws MappingException {
|
||||
String idProp = getIdentifierPropertyName();
|
||||
if ( idProp != null ) {
|
||||
propertyMapping.initPropertyPaths( idProp, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
|
||||
propertyMapping.initPropertyPaths( idProp, getIdentifierType(), getIdentifierColumnNames(),
|
||||
getIdentifierColumnReaders(), getIdentifierColumnReaderTemplates(), null, mapping );
|
||||
}
|
||||
if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
|
||||
propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
|
||||
propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(),
|
||||
getIdentifierColumnReaders(), getIdentifierColumnReaderTemplates(), null, mapping );
|
||||
}
|
||||
if ( ! entityMetamodel.hasNonIdentifierPropertyNamedId() ) {
|
||||
propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
|
||||
propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(),
|
||||
getIdentifierColumnReaders(), getIdentifierColumnReaderTemplates(), null, mapping );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1766,6 +1838,8 @@ public abstract class AbstractEntityPersister
|
|||
propertyMapping.initPropertyPaths( ENTITY_CLASS,
|
||||
getDiscriminatorType(),
|
||||
new String[]{getDiscriminatorColumnName()},
|
||||
new String[]{getDiscriminatorColumnReaders()},
|
||||
new String[]{getDiscriminatorColumnReaderTemplate()},
|
||||
new String[]{getDiscriminatorFormulaTemplate()},
|
||||
getFactory() );
|
||||
}
|
||||
|
@ -1838,17 +1912,17 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
// select the correct row by either pk or rowid
|
||||
if ( useRowId ) {
|
||||
update.setPrimaryKeyColumnNames( new String[]{rowIdName} ); //TODO: eventually, rowIdName[j]
|
||||
update.addPrimaryKeyColumns( new String[]{rowIdName} ); //TODO: eventually, rowIdName[j]
|
||||
}
|
||||
else {
|
||||
update.setPrimaryKeyColumnNames( getKeyColumns( j ) );
|
||||
update.addPrimaryKeyColumns( getKeyColumns( j ) );
|
||||
}
|
||||
|
||||
boolean hasColumns = false;
|
||||
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
// this is a property of the table, which we are updating
|
||||
update.addColumns( getPropertyColumnNames(i), propertyColumnUpdateable[i] );
|
||||
update.addColumns( getPropertyColumnNames(i), propertyColumnUpdateable[i], propertyColumnWriters[i] );
|
||||
hasColumns = hasColumns || getPropertyColumnSpan( i ) > 0;
|
||||
}
|
||||
}
|
||||
|
@ -1879,10 +1953,11 @@ public abstract class AbstractEntityPersister
|
|||
// this property belongs to the table, and it is not specifically
|
||||
// excluded from optimistic locking by optimistic-lock="false"
|
||||
String[] propertyColumnNames = getPropertyColumnNames( i );
|
||||
String[] propertyColumnWriters = getPropertyColumnWriters( i );
|
||||
boolean[] propertyNullness = types[i].toColumnNullness( oldFields[i], getFactory() );
|
||||
for ( int k=0; k<propertyNullness.length; k++ ) {
|
||||
if ( propertyNullness[k] ) {
|
||||
update.addWhereColumn( propertyColumnNames[k] );
|
||||
update.addWhereColumn( propertyColumnNames[k], "=" + propertyColumnWriters[k] );
|
||||
}
|
||||
else {
|
||||
update.addWhereColumn( propertyColumnNames[k], " is null" );
|
||||
|
@ -1928,7 +2003,7 @@ public abstract class AbstractEntityPersister
|
|||
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
|
||||
// this property belongs on the table and is to be inserted
|
||||
insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i] );
|
||||
insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i], propertyColumnWriters[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1976,7 +2051,7 @@ public abstract class AbstractEntityPersister
|
|||
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
|
||||
if ( includeProperty[i] && isPropertyOfTable( i, 0 ) ) {
|
||||
// this property belongs on the table and is to be inserted
|
||||
insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i] );
|
||||
insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i], propertyColumnWriters[i] );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1998,7 +2073,7 @@ public abstract class AbstractEntityPersister
|
|||
protected String generateDeleteString(int j) {
|
||||
Delete delete = new Delete()
|
||||
.setTableName( getTableName( j ) )
|
||||
.setPrimaryKeyColumnNames( getKeyColumns( j ) );
|
||||
.addPrimaryKeyColumns( getKeyColumns( j ) );
|
||||
if ( j == 0 ) {
|
||||
delete.setVersionColumnName( getVersionColumnName() );
|
||||
}
|
||||
|
@ -2750,7 +2825,7 @@ public abstract class AbstractEntityPersister
|
|||
for ( int j = span - 1; j >= 0; j-- ) {
|
||||
Delete delete = new Delete()
|
||||
.setTableName( getTableName( j ) )
|
||||
.setPrimaryKeyColumnNames( getKeyColumns( j ) );
|
||||
.addPrimaryKeyColumns( getKeyColumns( j ) );
|
||||
if ( getFactory().getSettings().isCommentsEnabled() ) {
|
||||
delete.setComment( "delete " + getEntityName() + " [" + j + "]" );
|
||||
}
|
||||
|
@ -2889,12 +2964,12 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
|
||||
String[] columnAliases = getSubclassColumnAliasClosure();
|
||||
String[] columns = getSubclassColumnClosure();
|
||||
String[] columnReaderTemplates = getSubclassColumnReaderTemplateClosure();
|
||||
for ( int i = 0; i < subclassColumnNumbers.length; i++ ) {
|
||||
int columnNumber = subclassColumnNumbers[i];
|
||||
if ( subclassColumnSelectableClosure[columnNumber] ) {
|
||||
final String subalias = generateTableAlias( getRootAlias(), columnTableNumbers[columnNumber] );
|
||||
selectFragment.addColumn( subalias, columns[columnNumber], columnAliases[columnNumber] );
|
||||
selectFragment.addColumnTemplate( subalias, columnReaderTemplates[columnNumber], columnAliases[columnNumber] );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -47,12 +47,22 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
|
||||
private final Map typesByPropertyPath = new HashMap();
|
||||
private final Map columnsByPropertyPath = new HashMap();
|
||||
private final Map columnReadersByPropertyPath = new HashMap();
|
||||
private final Map columnReaderTemplatesByPropertyPath = new HashMap();
|
||||
private final Map formulaTemplatesByPropertyPath = new HashMap();
|
||||
|
||||
public String[] getIdentifierColumnNames() {
|
||||
throw new UnsupportedOperationException("one-to-one is not supported here");
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaderTemplates() {
|
||||
throw new UnsupportedOperationException("one-to-one is not supported here");
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaders() {
|
||||
throw new UnsupportedOperationException("one-to-one is not supported here");
|
||||
}
|
||||
|
||||
protected abstract String getEntityName();
|
||||
|
||||
public Type toType(String propertyName) throws QueryException {
|
||||
|
@ -81,14 +91,15 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
if ( columns == null ) {
|
||||
throw propertyException( propertyName );
|
||||
}
|
||||
String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
|
||||
String[] formulaTemplates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
|
||||
String[] columnReaderTemplates = (String[]) columnReaderTemplatesByPropertyPath.get(propertyName);
|
||||
String[] result = new String[columns.length];
|
||||
for ( int i=0; i<columns.length; i++ ) {
|
||||
if ( columns[i]==null ) {
|
||||
result[i] = StringHelper.replace( templates[i], Template.TEMPLATE, alias );
|
||||
if ( columnReaderTemplates[i]==null ) {
|
||||
result[i] = StringHelper.replace( formulaTemplates[i], Template.TEMPLATE, alias );
|
||||
}
|
||||
else {
|
||||
result[i] = StringHelper.qualify( alias, columns[i] );
|
||||
result[i] = StringHelper.replace( columnReaderTemplates[i], Template.TEMPLATE, alias );
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -99,22 +110,27 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
if ( columns == null ) {
|
||||
throw propertyException( propertyName );
|
||||
}
|
||||
String[] templates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
|
||||
String[] formulaTemplates = (String[]) formulaTemplatesByPropertyPath.get(propertyName);
|
||||
String[] columnReaders = (String[]) columnReadersByPropertyPath.get(propertyName);
|
||||
String[] result = new String[columns.length];
|
||||
for ( int i=0; i<columns.length; i++ ) {
|
||||
if ( columns[i]==null ) {
|
||||
result[i] = StringHelper.replace( templates[i], Template.TEMPLATE, "" );
|
||||
if ( columnReaders[i]==null ) {
|
||||
result[i] = StringHelper.replace( formulaTemplates[i], Template.TEMPLATE, "" );
|
||||
}
|
||||
else {
|
||||
result[i] = columns[i];
|
||||
result[i] = columnReaders[i];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void addPropertyPath(String path, Type type, String[] columns, String[] formulaTemplates) {
|
||||
protected void addPropertyPath(String path, Type type, String[] columns,
|
||||
String[] columnReaders, String[] columnReaderTemplates,
|
||||
String[] formulaTemplates) {
|
||||
typesByPropertyPath.put(path, type);
|
||||
columnsByPropertyPath.put(path, columns);
|
||||
columnReadersByPropertyPath.put(path, columnReaders);
|
||||
columnReaderTemplatesByPropertyPath.put(path, columnReaderTemplates);
|
||||
if (formulaTemplates!=null) {
|
||||
formulaTemplatesByPropertyPath.put(path, formulaTemplates);
|
||||
}
|
||||
|
@ -135,6 +151,8 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
final String path,
|
||||
final Type type,
|
||||
String[] columns,
|
||||
String[] columnReaders,
|
||||
String[] columnReaderTemplates,
|
||||
final String[] formulaTemplates,
|
||||
final Mapping factory)
|
||||
throws MappingException {
|
||||
|
@ -150,6 +168,8 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
AssociationType actype = (AssociationType) type;
|
||||
if ( actype.useLHSPrimaryKey() ) {
|
||||
columns = getIdentifierColumnNames();
|
||||
columnReaders = getIdentifierColumnReaders();
|
||||
columnReaderTemplates = getIdentifierColumnReaderTemplates();
|
||||
}
|
||||
else {
|
||||
String foreignKeyProperty = actype.getLHSPropertyName();
|
||||
|
@ -158,27 +178,31 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
// referenced property in the mapping file (ok?)
|
||||
columns = (String[]) columnsByPropertyPath.get(foreignKeyProperty);
|
||||
if (columns==null) return; //get em on the second pass!
|
||||
columnReaders = (String[]) columnReadersByPropertyPath.get(foreignKeyProperty);
|
||||
columnReaderTemplates = (String[]) columnReaderTemplatesByPropertyPath.get(foreignKeyProperty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (path!=null) addPropertyPath(path, type, columns, formulaTemplates);
|
||||
if (path!=null) addPropertyPath(path, type, columns, columnReaders, columnReaderTemplates, formulaTemplates);
|
||||
|
||||
if ( type.isComponentType() ) {
|
||||
AbstractComponentType actype = (AbstractComponentType) type;
|
||||
initComponentPropertyPaths( path, actype, columns, formulaTemplates, factory );
|
||||
initComponentPropertyPaths( path, actype, columns, columnReaders, columnReaderTemplates, formulaTemplates, factory );
|
||||
if ( actype.isEmbedded() ) {
|
||||
initComponentPropertyPaths(
|
||||
path==null ? null : StringHelper.qualifier(path),
|
||||
actype,
|
||||
columns,
|
||||
columnReaders,
|
||||
columnReaderTemplates,
|
||||
formulaTemplates,
|
||||
factory
|
||||
);
|
||||
}
|
||||
}
|
||||
else if ( type.isEntityType() ) {
|
||||
initIdentifierPropertyPaths( path, (EntityType) type, columns, factory );
|
||||
initIdentifierPropertyPaths( path, (EntityType) type, columns, columnReaders, columnReaderTemplates, factory );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -186,6 +210,8 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
final String path,
|
||||
final EntityType etype,
|
||||
final String[] columns,
|
||||
final String[] columnReaders,
|
||||
final String[] columnReaderTemplates,
|
||||
final Mapping factory) throws MappingException {
|
||||
|
||||
Type idtype = etype.getIdentifierOrUniqueKeyType( factory );
|
||||
|
@ -195,15 +221,15 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
if ( etype.isReferenceToPrimaryKey() ) {
|
||||
if ( !hasNonIdentifierPropertyNamedId ) {
|
||||
String idpath1 = extendPath(path, EntityPersister.ENTITY_ID);
|
||||
addPropertyPath(idpath1, idtype, columns, null);
|
||||
initPropertyPaths(idpath1, idtype, columns, null, factory);
|
||||
addPropertyPath(idpath1, idtype, columns, columnReaders, columnReaderTemplates, null);
|
||||
initPropertyPaths(idpath1, idtype, columns, columnReaders, columnReaderTemplates, null, factory);
|
||||
}
|
||||
}
|
||||
|
||||
if (idPropName!=null) {
|
||||
String idpath2 = extendPath(path, idPropName);
|
||||
addPropertyPath(idpath2, idtype, columns, null);
|
||||
initPropertyPaths(idpath2, idtype, columns, null, factory);
|
||||
addPropertyPath(idpath2, idtype, columns, columnReaders, columnReaderTemplates, null);
|
||||
initPropertyPaths(idpath2, idtype, columns, columnReaders, columnReaderTemplates, null, factory);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -223,6 +249,8 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
final String path,
|
||||
final AbstractComponentType type,
|
||||
final String[] columns,
|
||||
final String[] columnReaders,
|
||||
final String[] columnReaderTemplates,
|
||||
String[] formulaTemplates, final Mapping factory)
|
||||
throws MappingException {
|
||||
|
||||
|
@ -234,9 +262,11 @@ public abstract class AbstractPropertyMapping implements PropertyMapping {
|
|||
try {
|
||||
int length = types[i].getColumnSpan(factory);
|
||||
String[] columnSlice = ArrayHelper.slice(columns, begin, length);
|
||||
String[] columnReaderSlice = ArrayHelper.slice(columnReaders, begin, length);
|
||||
String[] columnReaderTemplateSlice = ArrayHelper.slice(columnReaderTemplates, begin, length);
|
||||
String[] formulaSlice = formulaTemplates==null ?
|
||||
null : ArrayHelper.slice(formulaTemplates, begin, length);
|
||||
initPropertyPaths(subpath, types[i], columnSlice, formulaSlice, factory);
|
||||
initPropertyPaths(subpath, types[i], columnSlice, columnReaderSlice, columnReaderTemplateSlice, formulaSlice, factory);
|
||||
begin+=length;
|
||||
}
|
||||
catch (Exception e) {
|
||||
|
|
|
@ -41,6 +41,14 @@ public class BasicEntityPropertyMapping extends AbstractPropertyMapping {
|
|||
public String[] getIdentifierColumnNames() {
|
||||
return persister.getIdentifierColumnNames();
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaders() {
|
||||
return persister.getIdentifierColumnReaders();
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaderTemplates() {
|
||||
return persister.getIdentifierColumnReaderTemplates();
|
||||
}
|
||||
|
||||
protected String getEntityName() {
|
||||
return persister.getEntityName();
|
||||
|
|
|
@ -36,10 +36,10 @@ import org.hibernate.HibernateException;
|
|||
import org.hibernate.MappingException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.Mapping;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.Versioning;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.KeyValue;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
|
@ -65,7 +65,11 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
private final String[] tableNames;
|
||||
private final String[] naturalOrderTableNames;
|
||||
private final String[][] tableKeyColumns;
|
||||
private final String[][] tableKeyColumnReaders;
|
||||
private final String[][] tableKeyColumnReaderTemplates;
|
||||
private final String[][] naturalOrderTableKeyColumns;
|
||||
private final String[][] naturalOrderTableKeyColumnReaders;
|
||||
private final String[][] naturalOrderTableKeyColumnReaderTemplates;
|
||||
private final boolean[] naturalOrderCascadeDeleteEnabled;
|
||||
|
||||
private final String[] spaces;
|
||||
|
@ -139,6 +143,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
|
||||
ArrayList tables = new ArrayList();
|
||||
ArrayList keyColumns = new ArrayList();
|
||||
ArrayList keyColumnReaders = new ArrayList();
|
||||
ArrayList keyColumnReaderTemplates = new ArrayList();
|
||||
ArrayList cascadeDeletes = new ArrayList();
|
||||
Iterator titer = persistentClass.getTableClosureIterator();
|
||||
Iterator kiter = persistentClass.getKeyClosureIterator();
|
||||
|
@ -152,15 +158,24 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
);
|
||||
tables.add(tabname);
|
||||
String[] keyCols = new String[idColumnSpan];
|
||||
String[] keyColReaders = new String[idColumnSpan];
|
||||
String[] keyColReaderTemplates = new String[idColumnSpan];
|
||||
Iterator citer = key.getColumnIterator();
|
||||
for ( int k=0; k<idColumnSpan; k++ ) {
|
||||
keyCols[k] = ( (Column) citer.next() ).getQuotedName( factory.getDialect() );
|
||||
Column column = (Column) citer.next();
|
||||
keyCols[k] = column.getQuotedName( factory.getDialect() );
|
||||
keyColReaders[k] = column.getReadExpr( factory.getDialect() );
|
||||
keyColReaderTemplates[k] = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
}
|
||||
keyColumns.add(keyCols);
|
||||
keyColumnReaders.add(keyColReaders);
|
||||
keyColumnReaderTemplates.add(keyColReaderTemplates);
|
||||
cascadeDeletes.add( new Boolean( key.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete() ) );
|
||||
}
|
||||
naturalOrderTableNames = ArrayHelper.toStringArray(tables);
|
||||
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray(keyColumns);
|
||||
naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
|
||||
naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray(keyColumnReaderTemplates);
|
||||
naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray(cascadeDeletes);
|
||||
|
||||
ArrayList subtables = new ArrayList();
|
||||
|
@ -198,6 +213,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
tableSpan = naturalOrderTableNames.length;
|
||||
tableNames = reverse(naturalOrderTableNames);
|
||||
tableKeyColumns = reverse(naturalOrderTableKeyColumns);
|
||||
tableKeyColumnReaders = reverse(naturalOrderTableKeyColumnReaders);
|
||||
tableKeyColumnReaderTemplates = reverse(naturalOrderTableKeyColumnReaderTemplates);
|
||||
reverse(subclassTableNameClosure, tableSpan);
|
||||
reverse(subclassTableKeyColumnClosure, tableSpan);
|
||||
|
||||
|
@ -514,6 +531,14 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return tableKeyColumns[0];
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaderTemplates() {
|
||||
return tableKeyColumnReaderTemplates[0];
|
||||
}
|
||||
|
||||
public String[] getIdentifierColumnReaders() {
|
||||
return tableKeyColumnReaders[0];
|
||||
}
|
||||
|
||||
public String[] toColumns(String alias, String propertyName) throws QueryException {
|
||||
|
||||
if ( ENTITY_CLASS.equals(propertyName) ) {
|
||||
|
|
|
@ -35,9 +35,9 @@ import org.hibernate.EntityMode;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.cache.access.EntityRegionAccessStrategy;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.engine.Mapping;
|
||||
import org.hibernate.engine.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.Formula;
|
||||
import org.hibernate.mapping.Join;
|
||||
|
@ -102,6 +102,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
private final Map subclassesByDiscriminatorValue = new HashMap();
|
||||
private final boolean forceDiscriminator;
|
||||
private final String discriminatorColumnName;
|
||||
private final String discriminatorColumnReaders;
|
||||
private final String discriminatorColumnReaderTemplate;
|
||||
private final String discriminatorFormula;
|
||||
private final String discriminatorFormulaTemplate;
|
||||
private final String discriminatorAlias;
|
||||
|
@ -295,11 +297,15 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
discriminatorFormula = formula.getFormula();
|
||||
discriminatorFormulaTemplate = formula.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
discriminatorColumnName = null;
|
||||
discriminatorColumnReaders = null;
|
||||
discriminatorColumnReaderTemplate = null;
|
||||
discriminatorAlias = "clazz_";
|
||||
}
|
||||
else {
|
||||
Column column = (Column) selectable;
|
||||
discriminatorColumnName = column.getQuotedName( factory.getDialect() );
|
||||
discriminatorColumnReaders = column.getReadExpr( factory.getDialect() );
|
||||
discriminatorColumnReaderTemplate = column.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
|
||||
discriminatorAlias = column.getAlias( factory.getDialect(), persistentClass.getRootTable() );
|
||||
discriminatorFormula = null;
|
||||
discriminatorFormulaTemplate = null;
|
||||
|
@ -334,6 +340,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
forceDiscriminator = false;
|
||||
discriminatorInsertable = false;
|
||||
discriminatorColumnName = null;
|
||||
discriminatorColumnReaders = null;
|
||||
discriminatorColumnReaderTemplate = null;
|
||||
discriminatorAlias = null;
|
||||
discriminatorType = null;
|
||||
discriminatorValue = null;
|
||||
|
@ -444,6 +452,14 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
|
|||
return discriminatorColumnName;
|
||||
}
|
||||
|
||||
public String getDiscriminatorColumnReaders() {
|
||||
return discriminatorColumnReaders;
|
||||
}
|
||||
|
||||
public String getDiscriminatorColumnReaderTemplate() {
|
||||
return discriminatorColumnReaderTemplate;
|
||||
}
|
||||
|
||||
protected String getDiscriminatorAlias() {
|
||||
return discriminatorAlias;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,11 @@
|
|||
*/
|
||||
package org.hibernate.sql;
|
||||
|
||||
import org.hibernate.util.StringHelper;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import net.sf.cglib.transform.impl.AddPropertyTransformer;
|
||||
|
||||
/**
|
||||
* An SQL <tt>DELETE</tt> statement
|
||||
|
@ -34,10 +38,11 @@ import org.hibernate.util.StringHelper;
|
|||
public class Delete {
|
||||
|
||||
private String tableName;
|
||||
private String[] primaryKeyColumnNames;
|
||||
private String versionColumnName;
|
||||
private String where;
|
||||
|
||||
private Map primaryKeyColumns = new LinkedHashMap();
|
||||
|
||||
private String comment;
|
||||
public Delete setComment(String comment) {
|
||||
this.comment = comment;
|
||||
|
@ -55,12 +60,17 @@ public class Delete {
|
|||
buf.append( "/* " ).append(comment).append( " */ " );
|
||||
}
|
||||
buf.append( "delete from " ).append(tableName);
|
||||
if ( where != null || primaryKeyColumnNames != null || versionColumnName != null ) {
|
||||
if ( where != null || !primaryKeyColumns.isEmpty() || versionColumnName != null ) {
|
||||
buf.append( " where " );
|
||||
}
|
||||
boolean conditionsAppended = false;
|
||||
if ( primaryKeyColumnNames != null ) {
|
||||
buf.append( StringHelper.join( "=? and ", primaryKeyColumnNames ) ).append( "=?" );
|
||||
Iterator iter = primaryKeyColumns.entrySet().iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Map.Entry e = (Map.Entry) iter.next();
|
||||
buf.append( e.getKey() ).append( '=' ).append( e.getValue() );
|
||||
if ( iter.hasNext() ) {
|
||||
buf.append( " and " );
|
||||
}
|
||||
conditionsAppended = true;
|
||||
}
|
||||
if ( where!=null ) {
|
||||
|
@ -94,8 +104,35 @@ public class Delete {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Delete setPrimaryKeyColumnNames(String[] primaryKeyColumnNames) {
|
||||
this.primaryKeyColumnNames = primaryKeyColumnNames;
|
||||
public Delete setPrimaryKeyColumnNames(String[] columnNames) {
|
||||
this.primaryKeyColumns.clear();
|
||||
addPrimaryKeyColumns(columnNames);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Delete addPrimaryKeyColumns(String[] columnNames) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
addPrimaryKeyColumn( columnNames[i], "?" );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Delete addPrimaryKeyColumns(String[] columnNames, boolean[] includeColumns, String[] valueExpressions) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
if( includeColumns[i] ) addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Delete addPrimaryKeyColumns(String[] columnNames, String[] valueExpressions) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Delete addPrimaryKeyColumn(String columnName, String valueExpression) {
|
||||
this.primaryKeyColumns.put(columnName, valueExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,8 +25,8 @@
|
|||
package org.hibernate.sql;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.type.LiteralType;
|
||||
|
@ -75,8 +75,17 @@ public class Insert {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Insert addColumn(String columnName, String value) {
|
||||
columns.put(columnName, value);
|
||||
public Insert addColumns(String[] columnNames, boolean[] insertable, String[] valueExpressions) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
if ( insertable[i] ) {
|
||||
addColumn( columnNames[i], valueExpressions[i] );
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Insert addColumn(String columnName, String valueExpression) {
|
||||
columns.put(columnName, valueExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -121,7 +121,17 @@ public class SelectFragment {
|
|||
columnAliases.add(formulaAlias);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SelectFragment addColumnTemplate(String tableAlias, String columnTemplate, String columnAlias) {
|
||||
// In this context, there's no difference between a column template and a formula.
|
||||
return addFormula( tableAlias, columnTemplate, columnAlias );
|
||||
}
|
||||
|
||||
public SelectFragment addColumnTemplates(String tableAlias, String[] columnTemplates, String columnAliases[]) {
|
||||
// In this context, there's no difference between a column template and a formula.
|
||||
return addFormulas( tableAlias, columnTemplates, columnAliases );
|
||||
}
|
||||
|
||||
public String toFragmentString() {
|
||||
StringBuffer buf = new StringBuffer( columns.size() * 10 );
|
||||
Iterator iter = columns.iterator();
|
||||
|
|
|
@ -25,12 +25,11 @@
|
|||
package org.hibernate.sql;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.type.LiteralType;
|
||||
import org.hibernate.util.StringHelper;
|
||||
|
||||
/**
|
||||
* An SQL <tt>UPDATE</tt> statement
|
||||
|
@ -40,12 +39,12 @@ import org.hibernate.util.StringHelper;
|
|||
public class Update {
|
||||
|
||||
private String tableName;
|
||||
private String[] primaryKeyColumnNames;
|
||||
private String versionColumnName;
|
||||
private String where;
|
||||
private String assignments;
|
||||
private String comment;
|
||||
|
||||
private Map primaryKeyColumns = new LinkedHashMap();
|
||||
private Map columns = new LinkedHashMap();
|
||||
private Map whereColumns = new LinkedHashMap();
|
||||
|
||||
|
@ -74,11 +73,38 @@ public class Update {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Update setPrimaryKeyColumnNames(String[] primaryKeyColumnNames) {
|
||||
this.primaryKeyColumnNames = primaryKeyColumnNames;
|
||||
public Update setPrimaryKeyColumnNames(String[] columnNames) {
|
||||
this.primaryKeyColumns.clear();
|
||||
addPrimaryKeyColumns(columnNames);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Update addPrimaryKeyColumns(String[] columnNames) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
addPrimaryKeyColumn( columnNames[i], "?" );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Update addPrimaryKeyColumns(String[] columnNames, boolean[] includeColumns, String[] valueExpressions) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
if( includeColumns[i] ) addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Update addPrimaryKeyColumns(String[] columnNames, String[] valueExpressions) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
addPrimaryKeyColumn( columnNames[i], valueExpressions[i] );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Update addPrimaryKeyColumn(String columnName, String valueExpression) {
|
||||
this.primaryKeyColumns.put(columnName, valueExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Update setVersionColumnName(String versionColumnName) {
|
||||
this.versionColumnName = versionColumnName;
|
||||
return this;
|
||||
|
@ -89,7 +115,7 @@ public class Update {
|
|||
this.comment = comment;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public Update addColumns(String[] columnNames) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
addColumn( columnNames[i] );
|
||||
|
@ -97,16 +123,16 @@ public class Update {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Update addColumns(String[] columnNames, boolean[] updateable) {
|
||||
public Update addColumns(String[] columnNames, boolean[] updateable, String[] valueExpressions) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
if ( updateable[i] ) addColumn( columnNames[i] );
|
||||
if ( updateable[i] ) addColumn( columnNames[i], valueExpressions[i] );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public Update addColumns(String[] columnNames, String value) {
|
||||
public Update addColumns(String[] columnNames, String valueExpression) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
addColumn( columnNames[i], value );
|
||||
addColumn( columnNames[i], valueExpression );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -115,8 +141,8 @@ public class Update {
|
|||
return addColumn(columnName, "?");
|
||||
}
|
||||
|
||||
public Update addColumn(String columnName, String value) {
|
||||
columns.put(columnName, value);
|
||||
public Update addColumn(String columnName, String valueExpression) {
|
||||
columns.put(columnName, valueExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -131,9 +157,9 @@ public class Update {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Update addWhereColumns(String[] columnNames, String value) {
|
||||
public Update addWhereColumns(String[] columnNames, String valueExpression) {
|
||||
for ( int i=0; i<columnNames.length; i++ ) {
|
||||
addWhereColumn( columnNames[i], value );
|
||||
addWhereColumn( columnNames[i], valueExpression );
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
@ -142,8 +168,8 @@ public class Update {
|
|||
return addWhereColumn(columnName, "=?");
|
||||
}
|
||||
|
||||
public Update addWhereColumn(String columnName, String value) {
|
||||
whereColumns.put(columnName, value);
|
||||
public Update addWhereColumn(String columnName, String valueExpression) {
|
||||
whereColumns.put(columnName, valueExpression);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -176,11 +202,16 @@ public class Update {
|
|||
}
|
||||
|
||||
boolean conditionsAppended = false;
|
||||
if ( primaryKeyColumnNames != null || where != null || !whereColumns.isEmpty() || versionColumnName != null ) {
|
||||
if ( !primaryKeyColumns.isEmpty() || where != null || !whereColumns.isEmpty() || versionColumnName != null ) {
|
||||
buf.append( " where " );
|
||||
}
|
||||
if ( primaryKeyColumnNames != null ) {
|
||||
buf.append( StringHelper.join( "=? and ", primaryKeyColumnNames ) ).append( "=?" );
|
||||
iter = primaryKeyColumns.entrySet().iterator();
|
||||
while ( iter.hasNext() ) {
|
||||
Map.Entry e = (Map.Entry) iter.next();
|
||||
buf.append( e.getKey() ).append( '=' ).append( e.getValue() );
|
||||
if ( iter.hasNext() ) {
|
||||
buf.append( " and " );
|
||||
}
|
||||
conditionsAppended = true;
|
||||
}
|
||||
if ( where != null ) {
|
||||
|
|
|
@ -916,6 +916,8 @@ mapping associations to classes with composite ids. -->
|
|||
<!ATTLIST column index CDATA #IMPLIED>
|
||||
<!ATTLIST column check CDATA #IMPLIED> <!-- default: no check constraint -->
|
||||
<!ATTLIST column default CDATA #IMPLIED> <!-- default: no default value -->
|
||||
<!ATTLIST column read CDATA #IMPLIED> <!-- default: column name -->
|
||||
<!ATTLIST column write CDATA #IMPLIED> <!-- default: parameter placeholder ('?') -->
|
||||
|
||||
<!-- The formula and subselect elements allow us to map derived properties and
|
||||
entities. -->
|
||||
|
|
|
@ -2788,7 +2788,7 @@
|
|||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="mapping-column" revision="4">
|
||||
<sect2 id="mapping-column" revision="5">
|
||||
<title>Column and formula elements</title>
|
||||
<para>
|
||||
Mapping elements which accept a <literal>column</literal> attribute will alternatively
|
||||
|
@ -2807,12 +2807,22 @@
|
|||
index="index_name"
|
||||
sql-type="sql_type_name"
|
||||
check="SQL expression"
|
||||
default="SQL expression"/>]]></programlisting>
|
||||
default="SQL expression"
|
||||
read="SQL expression"
|
||||
write="SQL expression"/>]]></programlisting>
|
||||
|
||||
<programlisting><![CDATA[<formula>SQL expression</formula>]]></programlisting>
|
||||
|
||||
<para>
|
||||
<literal>column</literal> and <literal>formula</literal> attributes can even be combined
|
||||
Most of the attributes on <literal>column</literal> provide a means of tailoring the
|
||||
DDL during automatic schema generation. The <literal>read</literal> and <literal>write</literal>
|
||||
attributes allow you to specify custom SQL that Hibernate will use to access the column's value.
|
||||
For more on this, see the discussion of
|
||||
<link linkend="mapping-column-read-and-write">column read and write expressions</link>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <literal>column</literal> and <literal>formula</literal> elements can even be combined
|
||||
within the same property or association mapping to express, for example, exotic join
|
||||
conditions.
|
||||
</para>
|
||||
|
@ -3544,6 +3554,44 @@ public class Customer implements Serializable {
|
|||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="mapping-column-read-and-write" revision="1">
|
||||
<title>Column read and write expressions</title>
|
||||
<para>
|
||||
Hibernate allows you to customize the SQL it uses to read and write the values
|
||||
of columns mapped to <link linkend="mapping-declaration-property">simple properties</link>.
|
||||
For example, if your database provides a set of data encryption functions, you can
|
||||
invoke them for individual columns like this:
|
||||
<programlisting><![CDATA[<property name="creditCardNumber">
|
||||
<column
|
||||
name="credit_card_num"
|
||||
read="decrypt(credit_card_num)"
|
||||
write="encrypt(?)"/>
|
||||
</property>]]></programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Hibernate applies the custom expressions automatically whenever the property is
|
||||
referenced in a query. This functionality is similar to a derived-property
|
||||
<literal>formula</literal> with two differences:
|
||||
<itemizedlist spacing="compact">
|
||||
<listitem>
|
||||
<para>
|
||||
The property is backed by one or more columns that are exported as part of automatic
|
||||
schema generation.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The property is read-write, not read-only.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
The <literal>write</literal> expression, if specified, must contain exactly one '?' placeholder
|
||||
for the value.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="mapping-database-object">
|
||||
<title>Auxiliary database objects</title>
|
||||
<para>
|
||||
|
|
|
@ -662,10 +662,15 @@ BEGIN
|
|||
<sect1 id="querysql-cud">
|
||||
<title>Custom SQL for create, update and delete</title>
|
||||
|
||||
<para>Hibernate3 can use custom SQL statements for create, update, and
|
||||
delete operations. The class and collection persisters in Hibernate
|
||||
already contain a set of configuration time generated strings (insertsql,
|
||||
deletesql, updatesql etc.). The mapping tags
|
||||
<para>Hibernate3 can use custom SQL for create, update, and delete operations.
|
||||
The SQL can be overridden at the statement level or inidividual column level. This
|
||||
section describes statement overrides. For columns, see
|
||||
<xref linkend="mapping-column-read-and-write"/>.
|
||||
</para>
|
||||
<para>
|
||||
The class and collection persisters in Hibernate already contain a set of
|
||||
configuration time generated strings (insertsql, deletesql, updatesql etc.).
|
||||
The mapping tags
|
||||
<literal><sql-insert></literal>,
|
||||
<literal><sql-delete></literal>, and
|
||||
<literal><sql-update></literal> override these strings:</para>
|
||||
|
@ -732,7 +737,11 @@ END updatePerson;]]></programlisting>
|
|||
<title>Custom SQL for loading</title>
|
||||
|
||||
<para>You can also declare your own SQL (or HQL) queries for entity
|
||||
loading:</para>
|
||||
loading. As with inserts, updates, and deletes, this can be done at the
|
||||
individual column level as described in
|
||||
<xref linkend="mapping-column-read-and-write"/>
|
||||
or at the statement level. Here is an example of a statement level override:
|
||||
</para>
|
||||
|
||||
<programlisting><![CDATA[<sql-query name="person">
|
||||
<return alias="pers" class="Person" lock-mode="upgrade"/>
|
||||
|
|
|
@ -7,16 +7,17 @@ import java.util.List;
|
|||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.cfg.Mappings;
|
||||
import org.hibernate.criterion.Property;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.dialect.SybaseASE15Dialect;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
import org.hibernate.mapping.Component;
|
||||
|
@ -207,6 +208,48 @@ public class ComponentTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
User u = new User( "steve", "hibernater", new Person( "Steve Ebersole", new Date(), "Main St") );
|
||||
final double HEIGHT_INCHES = 73;
|
||||
final double HEIGHT_CENTIMETERS = HEIGHT_INCHES * 2.54d;
|
||||
u.getPerson().setHeightInches(HEIGHT_INCHES);
|
||||
s.persist( u );
|
||||
s.flush();
|
||||
|
||||
// Test value conversion during insert
|
||||
Double heightViaSql = (Double)s.createSQLQuery("select height_centimeters from t_user where t_user.username='steve'").uniqueResult();
|
||||
assertEquals(HEIGHT_CENTIMETERS, heightViaSql, 0.01d);
|
||||
|
||||
// Test projection
|
||||
Double heightViaHql = (Double)s.createQuery("select u.person.heightInches from User u where u.id = 'steve'").uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, heightViaHql, 0.01d);
|
||||
|
||||
// Test restriction and entity load via criteria
|
||||
u = (User)s.createCriteria(User.class)
|
||||
.add(Restrictions.between("person.heightInches", HEIGHT_INCHES - 0.01d, HEIGHT_INCHES + 0.01d))
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, u.getPerson().getHeightInches(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
u = (User)s.createQuery("from User u where u.person.heightInches between ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, u.getPerson().getHeightInches(), 0.01d);
|
||||
|
||||
// Test update
|
||||
u.getPerson().setHeightInches(1);
|
||||
s.flush();
|
||||
heightViaSql = (Double)s.createSQLQuery("select height_centimeters from t_user where t_user.username='steve'").uniqueResult();
|
||||
assertEquals(2.54d, heightViaSql, 0.01d);
|
||||
s.delete(u);
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
|
||||
public void testNamedQuery() {
|
||||
Session s = openSession();
|
||||
|
|
|
@ -13,6 +13,7 @@ public class Person {
|
|||
private String currentAddress;
|
||||
private String previousAddress;
|
||||
private int yob;
|
||||
private double heightInches;
|
||||
Person() {}
|
||||
public Person(String name, Date dob, String address) {
|
||||
this.name = name;
|
||||
|
@ -60,4 +61,10 @@ public class Person {
|
|||
public void setCurrentAddress(String currentAddress) {
|
||||
this.currentAddress = currentAddress;
|
||||
}
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,12 @@
|
|||
<property name="address"/>
|
||||
<property name="previousAddress" insert="false"/>
|
||||
<property name="yob" formula="year(dob)"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
<property name="currentAddress"
|
||||
column="address"
|
||||
insert="false"
|
||||
|
|
|
@ -9,6 +9,7 @@ public class Child {
|
|||
private String bio;
|
||||
private Parent parent;
|
||||
private int bioLength;
|
||||
private double heightInches;
|
||||
Child() {}
|
||||
public Child(String name) {
|
||||
this.name = name;
|
||||
|
@ -43,6 +44,12 @@ public class Child {
|
|||
public void setBio(String bio) {
|
||||
this.bio = bio;
|
||||
}
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
public int hashCode() {
|
||||
return name.hashCode();
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import junit.framework.Test;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.Mappings;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
|
@ -85,6 +86,52 @@ public class CompositeElementTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
final double HEIGHT_INCHES = 49;
|
||||
final double HEIGHT_CENTIMETERS = HEIGHT_INCHES * 2.54d;
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
Child c = new Child( "Child One" );
|
||||
c.setHeightInches(HEIGHT_INCHES);
|
||||
Parent p = new Parent( "Parent" );
|
||||
p.getChildren().add( c );
|
||||
c.setParent( p );
|
||||
s.save( p );
|
||||
s.flush();
|
||||
|
||||
// Test value conversion during insert
|
||||
Double heightViaSql = (Double)s.createSQLQuery("select height_centimeters from parentchild c where c.name='Child One'")
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_CENTIMETERS, heightViaSql, 0.01d);
|
||||
|
||||
// Test projection
|
||||
Double heightViaHql = (Double)s.createQuery("select c.heightInches from Parent p join p.children c where p.name='Parent'")
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, heightViaHql, 0.01d);
|
||||
|
||||
// Test entity load via criteria
|
||||
p = (Parent)s.createCriteria(Parent.class).add(Restrictions.eq("name", "Parent")).uniqueResult();
|
||||
c = (Child)p.getChildren().iterator().next();
|
||||
assertEquals(HEIGHT_INCHES, c.getHeightInches(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
p = (Parent)s.createQuery("from Parent p join p.children c where c.heightInches between ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
c = (Child)p.getChildren().iterator().next();
|
||||
assertEquals(HEIGHT_INCHES, c.getHeightInches(), 0.01d);
|
||||
|
||||
// Test update
|
||||
c.setHeightInches(1);
|
||||
s.flush();
|
||||
heightViaSql = (Double)s.createSQLQuery("select height_centimeters from parentchild c where c.name='Child One'").uniqueResult();
|
||||
assertEquals(2.54d, heightViaSql, 0.01d);
|
||||
s.delete( p );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -28,6 +28,12 @@
|
|||
<property name="name" not-null="true"/>
|
||||
<property name="bio"/>
|
||||
<property name="bioLength" formula="length(bio)"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
</composite-element>
|
||||
</set>
|
||||
</class>
|
||||
|
|
|
@ -8,6 +8,7 @@ import java.util.List;
|
|||
import junit.framework.Test;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.dialect.HSQLDialect;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
|
@ -57,6 +58,44 @@ public class CompositeUserTypeTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
Session s = openSession();
|
||||
org.hibernate.Transaction t = s.beginTransaction();
|
||||
final BigDecimal AMOUNT = new BigDecimal(73000000d);
|
||||
final BigDecimal AMOUNT_MILLIONS = AMOUNT.divide(new BigDecimal(1000000d));
|
||||
MutualFund f = new MutualFund();
|
||||
f.setHoldings( new MonetoryAmount( AMOUNT, Currency.getInstance("USD") ) );
|
||||
s.persist(f);
|
||||
s.flush();
|
||||
|
||||
// Test value conversion during insert
|
||||
BigDecimal amountViaSql = (BigDecimal)s.createSQLQuery("select amount_millions from MutualFund").uniqueResult();
|
||||
assertEquals(AMOUNT_MILLIONS.doubleValue(), amountViaSql.doubleValue(), 0.01d);
|
||||
|
||||
// Test projection
|
||||
BigDecimal amountViaHql = (BigDecimal)s.createQuery("select f.holdings.amount from MutualFund f").uniqueResult();
|
||||
assertEquals(AMOUNT.doubleValue(), amountViaHql.doubleValue(), 0.01d);
|
||||
|
||||
// Test restriction and entity load via criteria
|
||||
BigDecimal one = new BigDecimal(1);
|
||||
f = (MutualFund)s.createCriteria(MutualFund.class)
|
||||
.add(Restrictions.between("holdings.amount", AMOUNT.subtract(one), AMOUNT.add(one)))
|
||||
.uniqueResult();
|
||||
assertEquals(AMOUNT.doubleValue(), f.getHoldings().getAmount().doubleValue(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
f = (MutualFund)s.createQuery("from MutualFund f where f.holdings.amount between ? and ?")
|
||||
.setBigDecimal(0, AMOUNT.subtract(one))
|
||||
.setBigDecimal(1, AMOUNT.add(one))
|
||||
.uniqueResult();
|
||||
assertEquals(AMOUNT.doubleValue(), f.getHoldings().getAmount().doubleValue(), 0.01d);
|
||||
|
||||
s.delete(f);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package org.hibernate.test.cut;
|
||||
|
||||
/**
|
||||
* @author Rob.Hasselbaum
|
||||
*
|
||||
*/
|
||||
public class MutualFund {
|
||||
|
||||
private Long id;
|
||||
private MonetoryAmount holdings;
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public MonetoryAmount getHoldings() {
|
||||
return holdings;
|
||||
}
|
||||
|
||||
public void setHoldings(MonetoryAmount holdings) {
|
||||
this.holdings = holdings;
|
||||
}
|
||||
|
||||
}
|
|
@ -21,5 +21,18 @@
|
|||
<column name="currency" not-null="true"/>
|
||||
</property>
|
||||
</class>
|
||||
|
||||
<class name="MutualFund" table="MutualFund">
|
||||
<id name="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="holdings" type="money">
|
||||
<column name="amount_millions"
|
||||
not-null="true"
|
||||
read="amount_millions * 1000000.0"
|
||||
write="? / 1000000.0"/>
|
||||
<column name="currency" not-null="true"/>
|
||||
</property>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -11,21 +11,19 @@ import java.util.Set;
|
|||
|
||||
import junit.framework.Test;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.EntityMode;
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.Criteria;
|
||||
import org.hibernate.cache.CacheKey;
|
||||
import org.hibernate.cache.entry.CollectionCacheEntry;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.criterion.DetachedCriteria;
|
||||
import org.hibernate.criterion.Property;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.criterion.Subqueries;
|
||||
import org.hibernate.engine.SessionImplementor;
|
||||
import org.hibernate.impl.SessionFactoryImpl;
|
||||
|
@ -33,6 +31,8 @@ import org.hibernate.junit.functional.FunctionalTestCase;
|
|||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.transform.DistinctRootEntityResultTransformer;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Implementation of DynamicFilterTest.
|
||||
|
@ -179,6 +179,24 @@ public class DynamicFilterTest extends FunctionalTestCase {
|
|||
session.close();
|
||||
testData.release();
|
||||
}
|
||||
|
||||
public void testFiltersWithCustomerReadAndWrite() {
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Custom SQL read/write with filter
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
log.info( "Starting HQL filter with custom SQL get/set tests" );
|
||||
TestData testData = new TestData();
|
||||
testData.prepare();
|
||||
|
||||
Session session = openSession();
|
||||
session.enableFilter( "heavyProducts" ).setParameter("weightKilograms", 4d);
|
||||
log.info( "HQL against Product..." );
|
||||
List results = session.createQuery( "from Product").list();
|
||||
assertEquals( 1, results.size() );
|
||||
|
||||
session.close();
|
||||
testData.release();
|
||||
}
|
||||
|
||||
public void testCriteriaQueryFilters() {
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
@ -824,6 +842,7 @@ public class DynamicFilterTest extends FunctionalTestCase {
|
|||
Product product1 = new Product();
|
||||
product1.setName( "Acme Hair Gel" );
|
||||
product1.setStockNumber( 123 );
|
||||
product1.setWeightPounds( 0.25 );
|
||||
product1.setEffectiveStartDate( lastMonth.getTime() );
|
||||
product1.setEffectiveEndDate( nextMonth.getTime() );
|
||||
|
||||
|
@ -848,6 +867,7 @@ public class DynamicFilterTest extends FunctionalTestCase {
|
|||
Product product2 = new Product();
|
||||
product2.setName( "Acme Super-Duper DTO Factory" );
|
||||
product2.setStockNumber( 124 );
|
||||
product1.setWeightPounds( 10.0 );
|
||||
product2.setEffectiveStartDate( sixMonthsAgo.getTime() );
|
||||
product2.setEffectiveEndDate( new Date() );
|
||||
|
||||
|
|
|
@ -12,6 +12,12 @@
|
|||
|
||||
<property name="name" type="string"/>
|
||||
<property name="stockNumber" column="STOCK_NUM" type="int"/>
|
||||
<property name="weightPounds">
|
||||
<column name="weight_kg"
|
||||
not-null="true"
|
||||
write="0.453 * ?"
|
||||
read="weight_kg / 0.453"/>
|
||||
</property>
|
||||
|
||||
<property name="effectiveStartDate" column="eff_start_dt" type="java.util.Date"/>
|
||||
<property name="effectiveEndDate" column="eff_end_dt" type="java.util.Date"/>
|
||||
|
@ -30,7 +36,8 @@
|
|||
</set>
|
||||
|
||||
<filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/>
|
||||
<filter name="heavyProducts" condition=":weightKilograms < weight_kg"/>
|
||||
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
</hibernate-mapping>
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
// $Id: Product.java 6507 2005-04-25 16:57:32Z steveebersole $
|
||||
package org.hibernate.test.filter;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -14,6 +14,7 @@ public class Product {
|
|||
private int stockNumber; // int for ease of hashCode() impl
|
||||
private Date effectiveStartDate;
|
||||
private Date effectiveEndDate;
|
||||
private double weightPounds;
|
||||
private Set orderLineItems;
|
||||
private Set categories;
|
||||
|
||||
|
@ -73,6 +74,14 @@ public class Product {
|
|||
this.effectiveEndDate = effectiveEndDate;
|
||||
}
|
||||
|
||||
public double getWeightPounds() {
|
||||
return weightPounds;
|
||||
}
|
||||
|
||||
public void setWeightPounds(double weightPounds) {
|
||||
this.weightPounds = weightPounds;
|
||||
}
|
||||
|
||||
public Set getCategories() {
|
||||
return categories;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,10 @@
|
|||
<filter-param name="asOfDate" type="timestamp"/>
|
||||
</filter-def>
|
||||
|
||||
<filter-def name="heavyProducts">
|
||||
<filter-param name="weightKilograms" type="double"/>
|
||||
</filter-def>
|
||||
|
||||
<filter-def name="seniorSalespersons">
|
||||
<filter-param name="asOfDate" type="timestamp"/>
|
||||
</filter-def>
|
||||
|
@ -31,4 +35,4 @@
|
|||
<filter-def name="unioned">
|
||||
</filter-def>
|
||||
|
||||
</hibernate-mapping>
|
||||
</hibernate-mapping>
|
||||
|
|
|
@ -13,8 +13,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import junit.framework.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -30,7 +28,6 @@ import org.hibernate.dialect.DB2Dialect;
|
|||
import org.hibernate.dialect.HSQLDialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.dialect.Oracle8iDialect;
|
||||
|
||||
import org.hibernate.dialect.PostgreSQLDialect;
|
||||
import org.hibernate.dialect.SQLServerDialect;
|
||||
import org.hibernate.dialect.Sybase11Dialect;
|
||||
|
@ -55,6 +52,8 @@ import org.hibernate.type.ComponentType;
|
|||
import org.hibernate.type.ManyToOneType;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.util.StringHelper;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* Tests the integration of the new AST parser into the loading of query results using
|
||||
|
@ -82,6 +81,7 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
|||
"hql/FooBarCopy.hbm.xml",
|
||||
"hql/SimpleEntityWithAssociation.hbm.xml",
|
||||
"hql/CrazyIdFieldNames.hbm.xml",
|
||||
"hql/Image.hbm.xml",
|
||||
"batchfetch/ProductLine.hbm.xml",
|
||||
"cid/Customer.hbm.xml",
|
||||
"cid/Order.hbm.xml",
|
||||
|
@ -1085,6 +1085,101 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public void testOrderedWithCustomColumnReadAndWrite() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
SimpleEntityWithAssociation first = new SimpleEntityWithAssociation();
|
||||
first.setNegatedNumber(1);
|
||||
s.save(first);
|
||||
SimpleEntityWithAssociation second = new SimpleEntityWithAssociation();
|
||||
second.setNegatedNumber(2);
|
||||
s.save(second);
|
||||
s.flush();
|
||||
|
||||
// Check order via SQL. Numbers are negated in the DB, so second comes first.
|
||||
List listViaSql = s.createSQLQuery("select id from simple_1 order by negated_num").list();
|
||||
assertEquals(2, listViaSql.size());
|
||||
assertEquals(second.getId().longValue(), ((Number)listViaSql.get(0)).longValue());
|
||||
assertEquals(first.getId().longValue(), ((Number)listViaSql.get(1)).longValue());
|
||||
|
||||
// Check order via HQL. Now first comes first b/c the read negates the DB negation.
|
||||
List listViaHql = s.createQuery("from SimpleEntityWithAssociation order by negatedNumber").list();
|
||||
assertEquals(2, listViaHql.size());
|
||||
assertEquals(first.getId(), ((SimpleEntityWithAssociation)listViaHql.get(0)).getId());
|
||||
assertEquals(second.getId(), ((SimpleEntityWithAssociation)listViaHql.get(1)).getId());
|
||||
|
||||
s.delete(first);
|
||||
s.delete(second);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
public void testHavingWithCustomColumnReadAndWrite() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
SimpleEntityWithAssociation first = new SimpleEntityWithAssociation();
|
||||
first.setNegatedNumber(5);
|
||||
first.setName("simple");
|
||||
s.save(first);
|
||||
SimpleEntityWithAssociation second = new SimpleEntityWithAssociation();
|
||||
second.setNegatedNumber(10);
|
||||
second.setName("simple");
|
||||
s.save(second);
|
||||
SimpleEntityWithAssociation third = new SimpleEntityWithAssociation();
|
||||
third.setNegatedNumber(20);
|
||||
third.setName("complex");
|
||||
s.save(third);
|
||||
s.flush();
|
||||
|
||||
// Check order via HQL. Now first comes first b/c the read negates the DB negation.
|
||||
Number r = (Number)s.createQuery("select sum(negatedNumber) from SimpleEntityWithAssociation " +
|
||||
"group by name having sum(negatedNumber) < 20").uniqueResult();
|
||||
assertEquals(r.intValue(), 15);
|
||||
|
||||
s.delete(first);
|
||||
s.delete(second);
|
||||
s.delete(third);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
public void testLoadSnapshotWithCustomColumnReadAndWrite() {
|
||||
// Exercises entity snapshot load when select-before-update is true.
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
final double SIZE_IN_KB = 1536d;
|
||||
final double SIZE_IN_MB = SIZE_IN_KB / 1024d;
|
||||
Image image = new Image();
|
||||
image.setName("picture.gif");
|
||||
image.setSizeKb(SIZE_IN_KB);
|
||||
s.persist(image);
|
||||
s.flush();
|
||||
|
||||
Double sizeViaSql = (Double)s.createSQLQuery("select size_mb from image").uniqueResult();
|
||||
assertEquals(SIZE_IN_MB, sizeViaSql, 0.01d);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = openSession();
|
||||
t = s.beginTransaction();
|
||||
final double NEW_SIZE_IN_KB = 2048d;
|
||||
final double NEW_SIZE_IN_MB = NEW_SIZE_IN_KB / 1024d;
|
||||
image.setSizeKb(NEW_SIZE_IN_KB);
|
||||
s.update(image);
|
||||
s.flush();
|
||||
|
||||
sizeViaSql = (Double)s.createSQLQuery("select size_mb from image").uniqueResult();
|
||||
assertEquals(NEW_SIZE_IN_MB, sizeViaSql, 0.01d);
|
||||
|
||||
s.delete(image);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
private Human genSimpleHuman(String fName, String lName) {
|
||||
Human h = new Human();
|
||||
|
@ -1188,13 +1283,13 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
|||
Transaction t = s.beginTransaction();
|
||||
Human h = new Human();
|
||||
h.setBodyWeight( (float) 74.0 );
|
||||
h.setHeight(120.5);
|
||||
h.setHeightInches(120.5);
|
||||
h.setDescription("Me");
|
||||
h.setName( new Name("Gavin", 'A', "King") );
|
||||
h.setNickName("Oney");
|
||||
s.persist(h);
|
||||
Double sum = (Double) s.createQuery("select sum(h.bodyWeight) from Human h").uniqueResult();
|
||||
Double avg = (Double) s.createQuery("select avg(h.height) from Human h").uniqueResult();
|
||||
Double avg = (Double) s.createQuery("select avg(h.heightInches) from Human h").uniqueResult(); // uses custom read and write for column
|
||||
assertEquals(sum.floatValue(), 74.0, 0.01);
|
||||
assertEquals(avg.doubleValue(), 120.5, 0.01);
|
||||
Long id = (Long) s.createQuery("select max(a.id) from Animal a").uniqueResult();
|
||||
|
@ -1208,7 +1303,7 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
|||
Transaction t = s.beginTransaction();
|
||||
Human h = new Human();
|
||||
h.setBodyWeight( (float) 74.0 );
|
||||
h.setHeight(120.5);
|
||||
h.setHeightInches(120.5);
|
||||
h.setDescription("Me");
|
||||
h.setName( new Name("Gavin", 'A', "King") );
|
||||
h.setNickName("Oney");
|
||||
|
@ -1395,6 +1490,40 @@ public class ASTParserLoadingTest extends FunctionalTestCase {
|
|||
txn.commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
public void testFilterWithCustomColumnReadAndWrite() {
|
||||
Session session = openSession();
|
||||
Transaction txn = session.beginTransaction();
|
||||
|
||||
Human human = new Human();
|
||||
human.setName( new Name( "Steve", 'L', "Ebersole" ) );
|
||||
human.setHeightInches(73d);
|
||||
session.save( human );
|
||||
|
||||
Human friend = new Human();
|
||||
friend.setName( new Name( "John", 'Q', "Doe" ) );
|
||||
friend.setHeightInches(50d);
|
||||
session.save( friend );
|
||||
|
||||
human.setFriends( new ArrayList() );
|
||||
friend.setFriends( new ArrayList() );
|
||||
human.getFriends().add( friend );
|
||||
friend.getFriends().add( human );
|
||||
|
||||
session.flush();
|
||||
|
||||
assertEquals( session.createFilter( human.getFriends(), "" ).list().size(), 1 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.heightInches < ?" ).setDouble( 0, 51d ).list().size(), 1 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.heightInches > ?" ).setDouble( 0, 51d ).list().size(), 0 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.heightInches between 49 and 51" ).list().size(), 1 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.heightInches not between 49 and 51" ).list().size(), 0 );
|
||||
|
||||
session.delete(human);
|
||||
session.delete(friend);
|
||||
|
||||
txn.commit();
|
||||
session.close();
|
||||
}
|
||||
|
||||
public void testSelectExpressions() {
|
||||
createTestBaseData();
|
||||
|
|
|
@ -47,8 +47,12 @@
|
|||
<property name="last" column="name_last"/>
|
||||
</component>
|
||||
<property name="nickName"/>
|
||||
<property name="height"/>
|
||||
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
<property name="intValue"/>
|
||||
<property name="floatValue"/>
|
||||
<property name="bigDecimalValue"/>
|
||||
|
@ -147,4 +151,4 @@
|
|||
</join>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
</hibernate-mapping>
|
||||
|
|
|
@ -43,12 +43,12 @@ public class CriteriaClassicAggregationReturnTest extends QueryTranslatorTestCas
|
|||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] );
|
||||
|
||||
translator = createNewQueryTranslator( "select count(h.height) from Human h", sfi() );
|
||||
translator = createNewQueryTranslator( "select count(h.heightInches) from Human h", sfi() );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] );
|
||||
|
||||
// MAX, MIN return the type of the state-field to which they are applied.
|
||||
translator = createNewQueryTranslator( "select max(h.height) from Human h", sfi() );
|
||||
translator = createNewQueryTranslator( "select max(h.heightInches) from Human h", sfi() );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
|
||||
|
||||
|
@ -57,7 +57,7 @@ public class CriteriaClassicAggregationReturnTest extends QueryTranslatorTestCas
|
|||
assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
|
||||
|
||||
// AVG returns Float integrals, and otherwise the field type.
|
||||
translator = createNewQueryTranslator( "select avg(h.height) from Human h", sfi() );
|
||||
translator = createNewQueryTranslator( "select avg(h.heightInches) from Human h", sfi() );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
|
||||
|
||||
|
@ -78,7 +78,7 @@ public class CriteriaClassicAggregationReturnTest extends QueryTranslatorTestCas
|
|||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.INTEGER, translator.getReturnTypes()[0] );
|
||||
|
||||
translator = createNewQueryTranslator( "select sum(h.height) from Human h", sfi() );
|
||||
translator = createNewQueryTranslator( "select sum(h.heightInches) from Human h", sfi() );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
|
||||
|
||||
|
|
|
@ -47,12 +47,12 @@ public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase {
|
|||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
|
||||
|
||||
translator = createNewQueryTranslator( "select count(h.height) from Human h" );
|
||||
translator = createNewQueryTranslator( "select count(h.heightInches) from Human h" );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
|
||||
|
||||
// MAX, MIN return the type of the state-field to which they are applied.
|
||||
translator = createNewQueryTranslator( "select max(h.height) from Human h" );
|
||||
translator = createNewQueryTranslator( "select max(h.heightInches) from Human h" );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
|
||||
|
||||
|
@ -61,7 +61,7 @@ public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase {
|
|||
assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
|
||||
|
||||
// AVG returns Double.
|
||||
translator = createNewQueryTranslator( "select avg(h.height) from Human h" );
|
||||
translator = createNewQueryTranslator( "select avg(h.heightInches) from Human h" );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
|
||||
|
||||
|
@ -83,7 +83,7 @@ public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase {
|
|||
assertEquals( "incorrect return type", Hibernate.LONG, translator.getReturnTypes()[0] );
|
||||
|
||||
// SUM returns Double when applied to state-fields of floating point types;
|
||||
translator = createNewQueryTranslator( "select sum(h.height) from Human h" );
|
||||
translator = createNewQueryTranslator( "select sum(h.heightInches) from Human h" );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", Hibernate.DOUBLE, translator.getReturnTypes()[0] );
|
||||
|
||||
|
@ -123,18 +123,18 @@ public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase {
|
|||
// EJB3: COUNT returns Long
|
||||
Long longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.rowCount()).uniqueResult();
|
||||
assertEquals(longValue, new Long(1));
|
||||
longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.count("height")).uniqueResult();
|
||||
longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.count("heightInches")).uniqueResult();
|
||||
assertEquals(longValue, new Long(1));
|
||||
|
||||
// MAX, MIN return the type of the state-field to which they are applied.
|
||||
Double dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.max( "height" )).uniqueResult();
|
||||
Double dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.max( "heightInches" )).uniqueResult();
|
||||
assertNotNull(dblValue);
|
||||
|
||||
longValue = (Long) s.createCriteria( Human.class ).setProjection( Projections.max( "id" )).uniqueResult();
|
||||
assertNotNull(longValue);
|
||||
|
||||
// AVG returns Double.
|
||||
dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "height" )).uniqueResult();
|
||||
dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "heightInches" )).uniqueResult();
|
||||
assertNotNull(dblValue);
|
||||
|
||||
dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.avg( "id" )).uniqueResult();
|
||||
|
@ -151,7 +151,7 @@ public class CriteriaHQLAlignmentTest extends QueryTranslatorTestCase {
|
|||
assertNotNull(longValue);
|
||||
|
||||
// SUM returns Double when applied to state-fields of floating point types;
|
||||
dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.sum( "height" )).uniqueResult();
|
||||
dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.sum( "heightInches" )).uniqueResult();
|
||||
assertNotNull(dblValue);
|
||||
|
||||
dblValue = (Double) s.createCriteria( Human.class ).setProjection( Projections.sum( "floatValue" )).uniqueResult();
|
||||
|
|
|
@ -16,7 +16,7 @@ public class Human extends Mammal {
|
|||
private Collection friends;
|
||||
private Collection pets;
|
||||
private Map family;
|
||||
private double height;
|
||||
private double heightInches;
|
||||
|
||||
private BigInteger bigIntegerValue;
|
||||
private BigDecimal bigDecimalValue;
|
||||
|
@ -58,11 +58,12 @@ public class Human extends Mammal {
|
|||
this.nickName = nickName;
|
||||
}
|
||||
|
||||
public double getHeight() {
|
||||
return height;
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
public void setHeight(double height) {
|
||||
this.height = height;
|
||||
|
||||
public void setHeightInches(double height) {
|
||||
this.heightInches = height;
|
||||
}
|
||||
|
||||
public Map getFamily() {
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE hibernate-mapping PUBLIC
|
||||
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" >
|
||||
|
||||
<hibernate-mapping package="org.hibernate.test.hql">
|
||||
|
||||
<class name="Image" table="image" select-before-update="true" >
|
||||
<id name="id" type="java.lang.Long" column="id">
|
||||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="name" type="java.lang.String" column="name"/>
|
||||
<property name="sizeKb" lazy="true">
|
||||
<column name="size_mb"
|
||||
read="size_mb * 1024.0"
|
||||
write="? / 1024.0"/>
|
||||
</property>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
|
@ -0,0 +1,49 @@
|
|||
package org.hibernate.test.hql;
|
||||
|
||||
/**
|
||||
* @author Rob.Hasselbaum
|
||||
*/
|
||||
public class Image {
|
||||
|
||||
private Long id;
|
||||
private String name;
|
||||
private double sizeKb;
|
||||
|
||||
/**
|
||||
* @return the id
|
||||
*/
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
/**
|
||||
* @param id the id to set
|
||||
*/
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
/**
|
||||
* @return the name
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
/**
|
||||
* @param name the name to set
|
||||
*/
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
/**
|
||||
* @return the size in kb
|
||||
*/
|
||||
public double getSizeKb() {
|
||||
return sizeKb;
|
||||
}
|
||||
/**
|
||||
* @param sizeKb the size in kb to set
|
||||
*/
|
||||
public void setSizeKb(double sizeKb) {
|
||||
this.sizeKb = sizeKb;
|
||||
}
|
||||
|
||||
}
|
|
@ -11,6 +11,11 @@
|
|||
<generator class="native"/>
|
||||
</id>
|
||||
<property name="name" column="NAME" type="string"/>
|
||||
<property name="negatedNumber">
|
||||
<column name="negated_num"
|
||||
read="-negated_num"
|
||||
write="0 - ?"/>
|
||||
</property>
|
||||
<set name="associatedEntities" cascade="all" inverse="true" lazy="true">
|
||||
<key column="SIMPLE_1_ID"/>
|
||||
<one-to-many class="SimpleAssociatedEntity"/>
|
||||
|
@ -29,4 +34,4 @@
|
|||
<many-to-one name="owner" class="SimpleEntityWithAssociation" column="SIMPLE_1_ID"/>
|
||||
</class>
|
||||
|
||||
</hibernate-mapping>
|
||||
</hibernate-mapping>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package org.hibernate.test.hql;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -9,6 +9,7 @@ import java.util.HashSet;
|
|||
public class SimpleEntityWithAssociation {
|
||||
private Long id;
|
||||
private String name;
|
||||
private Integer negatedNumber;
|
||||
private Set associatedEntities = new HashSet();
|
||||
private Set manyToManyAssociatedEntities = new HashSet();
|
||||
|
||||
|
@ -34,6 +35,14 @@ public class SimpleEntityWithAssociation {
|
|||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Integer getNegatedNumber() {
|
||||
return negatedNumber;
|
||||
}
|
||||
|
||||
public void setNegatedNumber(Integer negatedNumber) {
|
||||
this.negatedNumber = negatedNumber;
|
||||
}
|
||||
|
||||
public Set getAssociatedEntities() {
|
||||
return associatedEntities;
|
||||
|
|
|
@ -5,18 +5,19 @@ import junit.framework.Test;
|
|||
import junit.framework.TestSuite;
|
||||
|
||||
import org.hibernate.intercept.FieldInterceptionHelper;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.junit.UnitTestCase;
|
||||
import org.hibernate.test.instrument.cases.Executable;
|
||||
import org.hibernate.test.instrument.cases.TestCustomColumnReadAndWrite;
|
||||
import org.hibernate.test.instrument.cases.TestDirtyCheckExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestFetchAllExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestInjectFieldInterceptorExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestIsPropertyInitializedExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyManyToOneExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestLazyPropertyCustomTypeExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestManyToOneProxyExecutable;
|
||||
import org.hibernate.test.instrument.cases.TestSharedPKOneToOneExecutable;
|
||||
import org.hibernate.test.instrument.cases.Executable;
|
||||
import org.hibernate.junit.UnitTestCase;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
|
@ -67,6 +68,10 @@ public class InstrumentTest extends UnitTestCase {
|
|||
execute( new TestSharedPKOneToOneExecutable() );
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() throws Exception {
|
||||
execute( new TestCustomColumnReadAndWrite() );
|
||||
}
|
||||
|
||||
private void execute(Executable executable) throws Exception {
|
||||
executable.prepare();
|
||||
try {
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package org.hibernate.test.instrument.cases;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static junit.framework.Assert.assertFalse;
|
||||
import static junit.framework.Assert.assertTrue;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.classic.Session;
|
||||
import org.hibernate.test.instrument.domain.Document;
|
||||
import org.hibernate.test.instrument.domain.Folder;
|
||||
import org.hibernate.test.instrument.domain.Owner;
|
||||
|
||||
/**
|
||||
* @author Rob.Hasselbaum
|
||||
*/
|
||||
public class TestCustomColumnReadAndWrite extends AbstractExecutable {
|
||||
public void execute() {
|
||||
Session s = getFactory().openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
final double SIZE_IN_KB = 20480;
|
||||
final double SIZE_IN_MB = SIZE_IN_KB / 1024d;
|
||||
Owner o = new Owner();
|
||||
Document doc = new Document();
|
||||
Folder fol = new Folder();
|
||||
o.setName("gavin");
|
||||
doc.setName("Hibernate in Action");
|
||||
doc.setSummary("blah");
|
||||
doc.updateText("blah blah");
|
||||
fol.setName("books");
|
||||
doc.setOwner(o);
|
||||
doc.setFolder(fol);
|
||||
doc.setSizeKb(SIZE_IN_KB);
|
||||
fol.getDocuments().add(doc);
|
||||
s.persist(o);
|
||||
s.persist(fol);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
|
||||
// Check value conversion on insert
|
||||
Double sizeViaSql = (Double)s.createSQLQuery("select size_mb from documents").uniqueResult();
|
||||
assertEquals( SIZE_IN_MB, sizeViaSql, 0.01d );
|
||||
|
||||
// Test explicit fetch of all properties
|
||||
doc = (Document) s.createQuery("from Document fetch all properties").uniqueResult();
|
||||
assertTrue( Hibernate.isPropertyInitialized( doc, "sizeKb" ) );
|
||||
assertEquals( SIZE_IN_KB, doc.getSizeKb() );
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
// Test lazy fetch with custom read
|
||||
s = getFactory().openSession();
|
||||
t = s.beginTransaction();
|
||||
doc = (Document) s.get( Document.class, doc.getId() );
|
||||
assertFalse( Hibernate.isPropertyInitialized( doc, "sizeKb" ) );
|
||||
assertEquals( SIZE_IN_KB, doc.getSizeKb() );
|
||||
s.delete(doc);
|
||||
s.delete( doc.getOwner() );
|
||||
s.delete( doc.getFolder() );
|
||||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ public class Document {
|
|||
private String text;
|
||||
private Owner owner;
|
||||
private Folder folder;
|
||||
private double sizeKb;
|
||||
private Date lastTextModification = new Date();
|
||||
/**
|
||||
* @return Returns the folder.
|
||||
|
@ -99,6 +100,18 @@ public class Document {
|
|||
public void setUpperCaseName(String upperCaseName) {
|
||||
this.upperCaseName = upperCaseName;
|
||||
}
|
||||
/**
|
||||
* @param sizeKb The size in KBs.
|
||||
*/
|
||||
public void setSizeKb(double sizeKb) {
|
||||
this.sizeKb = sizeKb;
|
||||
}
|
||||
/**
|
||||
* @return The size in KBs.
|
||||
*/
|
||||
public double getSizeKb() {
|
||||
return sizeKb;
|
||||
}
|
||||
|
||||
public void updateText(String newText) {
|
||||
if ( !newText.equals(text) ) {
|
||||
|
|
|
@ -53,6 +53,11 @@
|
|||
<many-to-one name="owner" not-null="true" lazy="no-proxy" fetch="select"/>
|
||||
<property name="text" not-null="true" length="2000" lazy="true"/>
|
||||
<property name="lastTextModification" not-null="true" lazy="true" access="field"/>
|
||||
<property name="sizeKb" lazy="true">
|
||||
<column name="size_mb"
|
||||
read="size_mb * 1024.0"
|
||||
write="? / 1024.0"/>
|
||||
</property>
|
||||
</class>
|
||||
|
||||
<class name="Entity" table="entity">
|
||||
|
|
|
@ -82,6 +82,10 @@ public abstract class AbstractTransformingClassLoaderInstrumentTestCase extends
|
|||
executeExecutable( "org.hibernate.test.instrument.cases.TestSharedPKOneToOneExecutable" );
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
executeExecutable( "org.hibernate.test.instrument.cases.TestCustomColumnReadAndWrite" );
|
||||
}
|
||||
|
||||
// reflection code to ensure isolation into the created classloader ~~~~~~~
|
||||
|
||||
private static final Class[] SIG = new Class[] {};
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
package org.hibernate.test.instrument.runtime;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.hibernate.bytecode.BytecodeProvider;
|
||||
import org.hibernate.bytecode.cglib.BytecodeProviderImpl;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -52,4 +53,9 @@ public class CGLIBInstrumentationTest extends AbstractTransformingClassLoaderIns
|
|||
public void testSharedPKOneToOne() {
|
||||
super.testSharedPKOneToOne();
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
super.testCustomColumnReadAndWrite();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
//$Id: $
|
||||
package org.hibernate.test.instrument.runtime;
|
||||
|
||||
import org.hibernate.bytecode.BytecodeProvider;
|
||||
import org.hibernate.bytecode.javassist.BytecodeProviderImpl;
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
import org.hibernate.bytecode.BytecodeProvider;
|
||||
import org.hibernate.bytecode.javassist.BytecodeProviderImpl;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -53,4 +54,9 @@ public class JavassistInstrumentationTest extends AbstractTransformingClassLoade
|
|||
public void testSharedPKOneToOne() {
|
||||
super.testSharedPKOneToOne();
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
super.testCustomColumnReadAndWrite();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import junit.framework.Test;
|
|||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
|
||||
|
@ -130,6 +131,82 @@ public class JoinTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
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;
|
||||
User u = new User();
|
||||
u.setName("Steve");
|
||||
u.setSex('M');
|
||||
u.setPasswordExpiryDays(PASSWORD_EXPIRY_DAYS);
|
||||
s.persist(u);
|
||||
s.flush();
|
||||
|
||||
// Test value conversion during insert
|
||||
Double heightViaSql = (Double)s.createSQLQuery("select height_centimeters from person where name='Emmanuel'").uniqueResult();
|
||||
assertEquals(HEIGHT_CENTIMETERS, heightViaSql, 0.01d);
|
||||
Double expiryViaSql = (Double)s.createSQLQuery("select pwd_expiry_weeks from t_user where person_id=?")
|
||||
.setLong(0, u.getId())
|
||||
.uniqueResult();
|
||||
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 u.passwordExpiryDays from User u where u.name = 'Steve'").uniqueResult();
|
||||
assertEquals(PASSWORD_EXPIRY_DAYS, expiryViaHql, 0.01d);
|
||||
|
||||
// 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();
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
u = (User)s.createCriteria(User.class)
|
||||
.add(Restrictions.between("passwordExpiryDays", PASSWORD_EXPIRY_DAYS - 0.01d, PASSWORD_EXPIRY_DAYS + 0.01d))
|
||||
.uniqueResult();
|
||||
assertEquals(PASSWORD_EXPIRY_DAYS, u.getPasswordExpiryDays(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
p = (Person)s.createQuery("from Person p where p.heightInches between ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
u = (User)s.createQuery("from User u where u.passwordExpiryDays between ? and ?")
|
||||
.setDouble(0, PASSWORD_EXPIRY_DAYS - 0.01d)
|
||||
.setDouble(1, PASSWORD_EXPIRY_DAYS + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(PASSWORD_EXPIRY_DAYS, u.getPasswordExpiryDays(), 0.01d);
|
||||
|
||||
// Test update
|
||||
p.setHeightInches(1);
|
||||
u.setPasswordExpiryDays(7d);
|
||||
s.flush();
|
||||
heightViaSql = (Double)s.createSQLQuery("select height_centimeters from person where name='Emmanuel'").uniqueResult();
|
||||
assertEquals(2.54d, heightViaSql, 0.01d);
|
||||
expiryViaSql = (Double)s.createSQLQuery("select pwd_expiry_weeks from t_user where person_id=?")
|
||||
.setLong(0, u.getId())
|
||||
.uniqueResult();
|
||||
assertEquals(1d, expiryViaSql, 0.01d);
|
||||
|
||||
s.delete(p);
|
||||
s.delete(u);
|
||||
assertTrue( s.createQuery("from Person").list().isEmpty() );
|
||||
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -36,6 +36,12 @@
|
|||
|
||||
<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.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
|
||||
<join table="address">
|
||||
<key column="address_id"/>
|
||||
|
@ -65,6 +71,11 @@
|
|||
<join table="t_user" fetch="select" optional="true">
|
||||
<key column="person_id"/>
|
||||
<property name="login" column="u_login"/>
|
||||
<property name="passwordExpiryDays">
|
||||
<column name="pwd_expiry_weeks"
|
||||
read="pwd_expiry_weeks * 7.0"
|
||||
write="? / 7.0"/>
|
||||
</property>
|
||||
</join>
|
||||
<join table="t_silly" fetch="select" optional="true">
|
||||
<key column="person_id"/>
|
||||
|
|
|
@ -11,6 +11,7 @@ public class Person {
|
|||
private String address;
|
||||
private String zip;
|
||||
private String country;
|
||||
private double heightInches;
|
||||
private char sex;
|
||||
|
||||
/**
|
||||
|
@ -77,6 +78,18 @@ public class Person {
|
|||
public void setZip(String zip) {
|
||||
this.zip = zip;
|
||||
}
|
||||
/**
|
||||
* @return the The height in inches.
|
||||
*/
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
/**
|
||||
* @param heightInches The height in inches.
|
||||
*/
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
/**
|
||||
* @param address The address to set.
|
||||
*/
|
||||
|
|
|
@ -7,6 +7,7 @@ package org.hibernate.test.join;
|
|||
public class User extends Person {
|
||||
private String login;
|
||||
private String silly;
|
||||
private Double passwordExpiryDays;
|
||||
|
||||
/**
|
||||
* @return Returns the login.
|
||||
|
@ -20,4 +21,16 @@ public class User extends Person {
|
|||
public void setLogin(String login) {
|
||||
this.login = login;
|
||||
}
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.math.BigDecimal;
|
|||
public class Employee extends Person {
|
||||
private String title;
|
||||
private BigDecimal salary;
|
||||
private double passwordExpiryDays;
|
||||
private Employee manager;
|
||||
/**
|
||||
* @return Returns the title.
|
||||
|
@ -46,4 +47,16 @@ public class Employee extends Person {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -179,6 +179,79 @@ public class JoinedSubclassTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
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
|
||||
Double heightViaSql = (Double)s.createSQLQuery("select height_centimeters from JPerson where name='Emmanuel'").uniqueResult();
|
||||
assertEquals(HEIGHT_CENTIMETERS, heightViaSql, 0.01d);
|
||||
Double expiryViaSql = (Double)s.createSQLQuery("select pwd_expiry_weeks from JEmployee where person_id=?")
|
||||
.setLong(0, e.getId())
|
||||
.uniqueResult();
|
||||
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
|
||||
p = (Person)s.createCriteria(Person.class)
|
||||
.add(Restrictions.between("heightInches", HEIGHT_INCHES - 0.01d, HEIGHT_INCHES + 0.01d))
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
e = (Employee)s.createCriteria(Employee.class)
|
||||
.add(Restrictions.between("passwordExpiryDays", PASSWORD_EXPIRY_DAYS - 0.01d, PASSWORD_EXPIRY_DAYS + 0.01d))
|
||||
.uniqueResult();
|
||||
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 ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
e = (Employee)s.createQuery("from Employee e where e.passwordExpiryDays between ? and ?")
|
||||
.setDouble(0, PASSWORD_EXPIRY_DAYS - 0.01d)
|
||||
.setDouble(1, 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 = (Double)s.createSQLQuery("select height_centimeters from JPerson where name='Emmanuel'").uniqueResult();
|
||||
assertEquals(2.54d, heightViaSql, 0.01d);
|
||||
expiryViaSql = (Double)s.createSQLQuery("select pwd_expiry_weeks from JEmployee where person_id=?")
|
||||
.setLong(0, e.getId())
|
||||
.uniqueResult();
|
||||
assertEquals(1d, expiryViaSql, 0.01d);
|
||||
s.delete(p);
|
||||
s.delete(e);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
public void testLockingJoinedSubclass() {
|
||||
Session s = openSession();
|
||||
|
|
|
@ -35,6 +35,12 @@
|
|||
<property name="sex"
|
||||
not-null="true"
|
||||
update="false"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
|
||||
<component name="address">
|
||||
<property name="address"/>
|
||||
|
@ -49,6 +55,12 @@
|
|||
length="20"/>
|
||||
<property name="salary"
|
||||
length="0"/>
|
||||
<property name="passwordExpiryDays">
|
||||
<column name="pwd_expiry_weeks"
|
||||
not-null="true"
|
||||
read="pwd_expiry_weeks * 7.0"
|
||||
write="? / 7.0"/>
|
||||
</property>
|
||||
<many-to-one name="manager"/>
|
||||
</joined-subclass>
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ public class Person {
|
|||
private String name;
|
||||
private char sex;
|
||||
private int version;
|
||||
private double heightInches;
|
||||
private Address address = new Address();
|
||||
/**
|
||||
* @return Returns the address.
|
||||
|
@ -68,6 +69,20 @@ public class Person {
|
|||
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;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ public class Alien {
|
|||
private String identity;
|
||||
private String planet;
|
||||
private String species;
|
||||
private double heightInches;
|
||||
|
||||
public void setIdentity(String identity) {
|
||||
this.identity = identity;
|
||||
|
@ -28,6 +29,12 @@ public class Alien {
|
|||
public String getPlanet() {
|
||||
return planet;
|
||||
}
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ public class Being {
|
|||
private String identity;
|
||||
private String location;
|
||||
private String species;
|
||||
private double heightInches;
|
||||
|
||||
public void setLocation(String location) {
|
||||
this.location = location;
|
||||
|
@ -28,4 +29,10 @@ public class Being {
|
|||
public String getIdentity() {
|
||||
return identity;
|
||||
}
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,6 +36,12 @@
|
|||
not-null="true"
|
||||
update="false"/>
|
||||
<property name="address"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
|
||||
</class>
|
||||
|
||||
|
@ -53,16 +59,22 @@
|
|||
<property name="species"
|
||||
not-null="true"
|
||||
update="false"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
|
||||
</class>
|
||||
|
||||
<class name="Being" mutable="false">
|
||||
|
||||
<subselect>
|
||||
select bid, name as ident, address as loc, 'human' as species
|
||||
select bid, name as ident, address as loc, 'human' as species, height_centimeters
|
||||
from humans
|
||||
union
|
||||
select bid, ident, planet as loc, species
|
||||
select bid, ident, planet as loc, species, height_centimeters
|
||||
from aliens
|
||||
</subselect>
|
||||
|
||||
|
@ -77,6 +89,11 @@
|
|||
<property name="identity" column="ident"/>
|
||||
<property name="location" column="loc"/>
|
||||
<property name="species"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"/>
|
||||
</property>
|
||||
|
||||
</class>
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ public class Human {
|
|||
private String name;
|
||||
private char sex;
|
||||
private String address;
|
||||
private double heightInches;
|
||||
|
||||
public void setAddress(String address) {
|
||||
this.address = address;
|
||||
|
@ -34,4 +35,10 @@ public class Human {
|
|||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
public double getHeightInches() {
|
||||
return heightInches;
|
||||
}
|
||||
public void setHeightInches(double heightInches) {
|
||||
this.heightInches = heightInches;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import junit.framework.Test;
|
|||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.junit.functional.FunctionalTestCase;
|
||||
import org.hibernate.junit.functional.FunctionalTestClassTestSuite;
|
||||
|
||||
|
@ -67,6 +68,57 @@ public class SubselectTest extends FunctionalTestCase {
|
|||
t.commit();
|
||||
s.close();
|
||||
}
|
||||
|
||||
public void testCustomColumnReadAndWrite() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
final double HUMAN_INCHES = 73;
|
||||
final double ALIEN_INCHES = 931;
|
||||
final double HUMAN_CENTIMETERS = HUMAN_INCHES * 2.54d;
|
||||
final double ALIEN_CENTIMETERS = ALIEN_INCHES * 2.54d;
|
||||
Human gavin = new Human();
|
||||
gavin.setName( "gavin" );
|
||||
gavin.setSex( 'M' );
|
||||
gavin.setAddress( "Melbourne, Australia" );
|
||||
gavin.setHeightInches( HUMAN_INCHES );
|
||||
Alien x23y4 = new Alien();
|
||||
x23y4.setIdentity( "x23y4$$hu%3" );
|
||||
x23y4.setPlanet( "Mars" );
|
||||
x23y4.setSpecies( "martian" );
|
||||
x23y4.setHeightInches( ALIEN_INCHES );
|
||||
s.save(gavin);
|
||||
s.save(x23y4);
|
||||
s.flush();
|
||||
|
||||
// Test value conversion during insert
|
||||
Double humanHeightViaSql = (Double)s.createSQLQuery("select height_centimeters from humans").uniqueResult();
|
||||
assertEquals(HUMAN_CENTIMETERS, humanHeightViaSql, 0.01d);
|
||||
Double alienHeightViaSql = (Double)s.createSQLQuery("select height_centimeters from aliens").uniqueResult();
|
||||
assertEquals(ALIEN_CENTIMETERS, alienHeightViaSql, 0.01d);
|
||||
s.clear();
|
||||
|
||||
// Test projection
|
||||
Double heightViaHql = (Double)s.createQuery("select heightInches from Being b where b.identity = 'gavin'").uniqueResult();
|
||||
assertEquals(HUMAN_INCHES, heightViaHql, 0.01d);
|
||||
|
||||
// Test restriction and entity load via criteria
|
||||
Being b = (Being)s.createCriteria(Being.class)
|
||||
.add(Restrictions.between("heightInches", HUMAN_INCHES - 0.01d, HUMAN_INCHES + 0.01d))
|
||||
.uniqueResult();
|
||||
assertEquals(HUMAN_INCHES, b.getHeightInches(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
b = (Being)s.createQuery("from Being b where b.heightInches between ? and ?")
|
||||
.setDouble(0, ALIEN_INCHES - 0.01d)
|
||||
.setDouble(1, ALIEN_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(ALIEN_INCHES, b.getHeightInches(), 0.01d);
|
||||
s.delete(gavin);
|
||||
s.delete(x23y4);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ import java.math.BigDecimal;
|
|||
public class Employee extends Person {
|
||||
private String title;
|
||||
private BigDecimal salary;
|
||||
private double passwordExpiryDays;
|
||||
private Employee manager;
|
||||
/**
|
||||
* @return Returns the title.
|
||||
|
@ -46,4 +47,16 @@ public class Employee extends Person {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,6 +34,12 @@
|
|||
<property name="sex"
|
||||
not-null="true"
|
||||
update="false"/>
|
||||
<property name="heightInches">
|
||||
<column name="height_centimeters"
|
||||
not-null="true"
|
||||
read="height_centimeters / 2.54"
|
||||
write="? * 2.54"/>
|
||||
</property>
|
||||
|
||||
<component name="address">
|
||||
<property name="address" index="AddressIndex"/>
|
||||
|
@ -47,6 +53,12 @@
|
|||
length="20"/>
|
||||
<property name="salary"
|
||||
length="0"/>
|
||||
<property name="passwordExpiryDays">
|
||||
<column name="pwd_expiry_weeks"
|
||||
not-null="true"
|
||||
read="pwd_expiry_weeks * 7.0"
|
||||
write="? / 7.0"/>
|
||||
</property>
|
||||
<many-to-one name="manager"/>
|
||||
</union-subclass>
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ public class Person {
|
|||
private long id;
|
||||
private String name;
|
||||
private char sex;
|
||||
private double heightInches;
|
||||
private Address address = new Address();
|
||||
/**
|
||||
* @return Returns the address.
|
||||
|
@ -66,5 +67,16 @@ public class Person {
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,5 +149,79 @@ public class UnionSubclassTest extends FunctionalTestCase {
|
|||
s.close();
|
||||
}
|
||||
|
||||
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
|
||||
Double heightViaSql = (Double)s.createSQLQuery("select height_centimeters from UPerson where name='Emmanuel'").uniqueResult();
|
||||
assertEquals(HEIGHT_CENTIMETERS, heightViaSql, 0.01d);
|
||||
Double expiryViaSql = (Double)s.createSQLQuery("select pwd_expiry_weeks from UEmployee where person_id=?")
|
||||
.setLong(0, e.getId())
|
||||
.uniqueResult();
|
||||
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
|
||||
p = (Person)s.createCriteria(Person.class)
|
||||
.add(Restrictions.between("heightInches", HEIGHT_INCHES - 0.01d, HEIGHT_INCHES + 0.01d))
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
e = (Employee)s.createCriteria(Employee.class)
|
||||
.add(Restrictions.between("passwordExpiryDays", PASSWORD_EXPIRY_DAYS - 0.01d, PASSWORD_EXPIRY_DAYS + 0.01d))
|
||||
.uniqueResult();
|
||||
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 ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
e = (Employee)s.createQuery("from Employee e where e.passwordExpiryDays between ? and ?")
|
||||
.setDouble(0, PASSWORD_EXPIRY_DAYS - 0.01d)
|
||||
.setDouble(1, 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 = (Double)s.createSQLQuery("select height_centimeters from UPerson where name='Emmanuel'").uniqueResult();
|
||||
assertEquals(2.54d, heightViaSql, 0.01d);
|
||||
expiryViaSql = (Double)s.createSQLQuery("select pwd_expiry_weeks from UEmployee where person_id=?")
|
||||
.setLong(0, e.getId())
|
||||
.uniqueResult();
|
||||
assertEquals(1d, expiryViaSql, 0.01d);
|
||||
s.delete(p);
|
||||
s.delete(e);
|
||||
t.commit();
|
||||
s.close();
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue