📄 normalizedentitypersister.java
字号:
//$Id: NormalizedEntityPersister.java,v 1.32.2.37 2003/11/29 06:52:55 oneovthafew Exp $package net.sf.hibernate.persister;import net.sf.hibernate.util.ArrayHelper;import net.sf.hibernate.util.JDBCExceptionReporter;import net.sf.hibernate.util.StringHelper;import net.sf.hibernate.loader.UniqueEntityLoader;import net.sf.hibernate.mapping.Column;import net.sf.hibernate.mapping.PersistentClass;import net.sf.hibernate.mapping.Property;import net.sf.hibernate.mapping.Subclass;import net.sf.hibernate.mapping.Table;import java.io.Serializable;import java.sql.PreparedStatement;import java.sql.ResultSet;import java.sql.SQLException;import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.Map;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import net.sf.hibernate.AssertionFailure;import net.sf.hibernate.Hibernate;import net.sf.hibernate.HibernateException;import net.sf.hibernate.JDBCException;import net.sf.hibernate.LockMode;import net.sf.hibernate.MappingException;import net.sf.hibernate.QueryException;import net.sf.hibernate.StaleObjectStateException;import net.sf.hibernate.id.IdentifierGeneratorFactory;import net.sf.hibernate.impl.MessageHelper;import net.sf.hibernate.sql.CaseFragment;import net.sf.hibernate.sql.Delete;import net.sf.hibernate.sql.Insert;import net.sf.hibernate.sql.JoinFragment;import net.sf.hibernate.sql.SimpleSelect;import net.sf.hibernate.sql.SelectFragment;import net.sf.hibernate.sql.Update;import net.sf.hibernate.type.AssociationType;import net.sf.hibernate.type.DiscriminatorType;import net.sf.hibernate.type.Type;import net.sf.hibernate.engine.SessionFactoryImplementor;import net.sf.hibernate.engine.SessionImplementor;import net.sf.hibernate.engine.Versioning;/** * A <tt>ClassPersister</tt> implementing the normalized "table-per-subclass" mapping strategy. * * @author Gavin King */public class NormalizedEntityPersister extends AbstractEntityPersister { private final SessionFactoryImplementor factory; // the class hierarchy structure private final String qualifiedTableName; private final String[] tableNames; private final String[] naturalOrderTableNames; private final String[][] tableKeyColumns; private final String[][] naturalOrderTableKeyColumns; private final Class[] subclassClosure; private final String[] subclassTableNameClosure; private final String[][] subclassTableKeyColumns; private final boolean[] isClassOrSuperclassTable; // SQL strings private final String[] sqlDeleteStrings; private final String[] sqlInsertStrings; private final String[] sqlIdentityInsertStrings; private final String[] sqlUpdateStrings; // properties of this class, including inherited properties private final int[] propertyColumnSpans; private final int[] propertyTables; private final int[] naturalOrderPropertyTables; private final boolean[] propertyHasColumns; private final String[][] propertyColumnNames; private final String[][] propertyColumnAliases; private final String[] propertyFormulaTemplates; // the closure of all properties in the entire hierarchy including // subclasses and superclasses of this class private final String[][] subclassPropertyColumnNameClosure; private final int[] subclassPropertyTableNumberClosure; private final Type[] subclassPropertyTypeClosure; private final String[] subclassPropertyNameClosure; private final int[] subclassPropertyEnableJoinedFetch; private final boolean[] propertyDefinedOnSubclass; private final HashMap tableNumberByPropertyPath = new HashMap(); // the closure of all columns used by the entire hierarchy including // subclasses and superclasses of this class private final int[] subclassColumnTableNumberClosure; private final String[] subclassColumnClosure; private final String[] subclassColumnClosureAliases; private final int[] subclassFormulaTableNumberClosure; private final String[] subclassFormulaTemplateClosure; private final String[] subclassFormulaAliasClosure; // subclass discrimination works by assigning particular // values to certain combinations of null primary key // values in the outer join using an SQL CASE private final HashMap subclassesByDiscriminatorValue = new HashMap(); private final String[] discriminatorValues; private final String[] notNullColumns; private final int[] tableNumbers; private final DiscriminatorType discriminatorType; private final String discriminatorSQLString; private final String discriminatorColumnName; private final String sqlConcreteSelectString; private final String sqlVersionSelectString; private UniqueEntityLoader loader; private final Map lockers = new HashMap(); private static final Log log = LogFactory.getLog(NormalizedEntityPersister.class); public void postInstantiate() throws MappingException { initPropertyPaths(factory); loader = createEntityLoader(factory); createUniqueKeyLoaders(factory); } public boolean isDefinedOnSubclass(int i) { return propertyDefinedOnSubclass[i]; } public String getDiscriminatorColumnName() { return discriminatorColumnName; } public String getDiscriminatorAlias() { return getDiscriminatorColumnName(); // is always "clazz_", so just use columnname } public Type getSubclassPropertyType(int i) { return subclassPropertyTypeClosure[i]; } public String getSubclassPropertyName(int i) { return subclassPropertyNameClosure[i]; } public int countSubclassProperties() { return subclassPropertyTypeClosure.length; } public String getSubclassPropertyTableName(int i) { return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ]; } public String[] getSubclassPropertyColumnNames(int i) { return subclassPropertyColumnNameClosure[i]; } public String[] getPropertyColumnNames(int i) { return propertyColumnAliases[i]; } public Type getDiscriminatorType() { return discriminatorType; } public Object getDiscriminatorSQLValue() { return discriminatorSQLString; } public Class getSubclassForDiscriminatorValue(Object value) { return (Class) subclassesByDiscriminatorValue.get(value); } public int enableJoinedFetch(int i) { return subclassPropertyEnableJoinedFetch[i]; } public Serializable getIdentifierSpace() { return qualifiedTableName; } public Serializable[] getPropertySpaces() { return tableNames; // don't need subclass tables, because they can't appear in conditions } //Access cached SQL /** * The queries that delete rows by id (and version) */ protected final String[] getSQLDeleteStrings() { return sqlDeleteStrings; } /** * The queries that insert rows with a given id */ protected final String[] getSQLInsertStrings() { return sqlInsertStrings; } /** * The queries that insert rows, letting the database generate an id */ protected final String[] getSQLIdentityInsertStrings() { return sqlIdentityInsertStrings; } /** * The queries that update rows by id (and version) */ protected final String[] getSQLUpdateStrings() { return sqlUpdateStrings; } protected final String getVersionSelectString() { return sqlVersionSelectString; } // Generate all the SQL /** * Generate the SQL that deletes rows by id (and version) */ protected String[] generateDeleteStrings() { String[] result = new String[ naturalOrderTableNames.length ]; for ( int i=0; i<naturalOrderTableNames.length; i++ ) { Delete delete = new Delete() .setTableName( naturalOrderTableNames[i] ) .setPrimaryKeyColumnNames( naturalOrderTableKeyColumns[i] ); if (i==0) delete.setVersionColumnName( getVersionColumnName() ); result[i] = delete.toStatementString(); } return result; } /** * Generate the SQL that inserts rows */ protected String[] generateInsertStrings(boolean identityInsert, boolean[] includeProperty) { String[] result = new String[naturalOrderTableNames.length]; for ( int j=0; j<naturalOrderTableNames.length; j++ ) { Insert insert = new Insert( getDialect() ) .setTableName( naturalOrderTableNames[j] ); for (int i=0; i<getPropertyTypes().length; i++) { if ( includeProperty[i] && naturalOrderPropertyTables[i]==j ) { insert.addColumns( propertyColumnNames[i] ); } } if (identityInsert && j==0) { insert.addIdentityColumn( naturalOrderTableKeyColumns[j][0] ); } else { insert.addColumns( naturalOrderTableKeyColumns[j] ); } result[j] = insert.toStatementString(); } return result; } /** * Generate the SQL that updates rows by id (and version) */ protected String[] generateUpdateStrings(boolean[] includeProperty) { String[] result = new String[ naturalOrderTableNames.length ]; for ( int j=0; j<naturalOrderTableNames.length; j++ ) { Update update = new Update() .setTableName( naturalOrderTableNames[j] ) .setPrimaryKeyColumnNames( naturalOrderTableKeyColumns[j] ); if (j==0) update.setVersionColumnName( getVersionColumnName() ); boolean hasColumns = false; for (int i=0; i<propertyColumnNames.length; i++) { if ( includeProperty[i] && naturalOrderPropertyTables[i]==j ) { update.addColumns( propertyColumnNames[i] ); hasColumns = hasColumns || propertyColumnNames[i].length > 0; } } result[j] = hasColumns ? update.toStatementString() : null; } return result; } /** * Generate the SQL that pessimistic locks a row by id (and version) */ protected String generateLockString() { SimpleSelect select = new SimpleSelect() .setTableName(qualifiedTableName) .addColumn( super.getIdentifierColumnNames()[0] ) .addCondition( super.getIdentifierColumnNames(), "=?" ); if ( isVersioned() ) { select.addWhereToken("and") .addCondition( getVersionColumnName(), "=?" ); } return select.toStatementString(); } /** * Generate the SQL that selects a row by id, excluding subclasses */ protected String getConcreteSelectString() { return sqlConcreteSelectString; } private static final String CONCRETE_ALIAS = "x"; protected String generateConcreteSelectString() { String select = "select " + StringHelper.join( StringHelper.COMMA_SPACE, StringHelper.qualify( CONCRETE_ALIAS, getIdentifierColumnNames() ) ) + concretePropertySelectFragment( CONCRETE_ALIAS, getPropertyUpdateability() ) + " from " + fromTableFragment(CONCRETE_ALIAS) + fromJoinFragment(CONCRETE_ALIAS, true, false) + " where " + whereJoinFragment(CONCRETE_ALIAS, true, false) + StringHelper.join( "=? and ", StringHelper.qualify( CONCRETE_ALIAS, getIdentifierColumnNames() ) ) + "=?"; if ( isVersioned() ) { select += " and " + getVersionColumnName() + "=?"; } return select; } /** * Marshall the fields of a persistent instance to a prepared statement */ protected int dehydrate(Serializable id, Object[] fields, boolean[] includeProperty, PreparedStatement[] statements, SessionImplementor session) throws SQLException, HibernateException { if ( log.isTraceEnabled() ) log.trace( "Dehydrating entity: " + MessageHelper.infoString(this, id) ); int versionParam = 0; for ( int i=0; i<tableNames.length; i++ ) { int index = dehydrate(id, fields, includeProperty, i, statements[i], session); if (i==0) versionParam = index; } return versionParam; } private int dehydrate(Serializable id, Object[] fields, boolean[] includeProperty, int table, PreparedStatement statement, SessionImplementor session) throws SQLException, HibernateException { if (statement==null) return -1; int index = 1; for (int j=0; j<getHydrateSpan(); j++) { if ( includeProperty[j] && naturalOrderPropertyTables[j]==table ) { getPropertyTypes()[j].nullSafeSet( statement, fields[j], index, session ); index += propertyColumnSpans[j]; } } if ( id!=null ) { getIdentifierType().nullSafeSet( statement, id, index, session ); index+=getIdentifierColumnNames().length; } return index; } // Execute the SQL: /** * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>, * depending upon the value of the <tt>lock</tt> parameter */ public Object load(Serializable id, Object optionalObject, LockMode lockMode, SessionImplementor session) throws HibernateException { if ( log.isTraceEnabled() ) log.trace( "Materializing entity: " + MessageHelper.infoString(this, id) ); try { Object result = loader.load(session, id, optionalObject); if (result!=null) lock(id, getVersion(result), result, lockMode, session); return result;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -