Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » persister » entity » [javadoc | source]
    1   /*
    2    * Hibernate, Relational Persistence for Idiomatic Java
    3    *
    4    * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
    5    * indicated by the @author tags or express copyright attribution
    6    * statements applied by the authors.  All third-party contributions are
    7    * distributed under license by Red Hat Middleware LLC.
    8    *
    9    * This copyrighted material is made available to anyone wishing to use, modify,
   10    * copy, or redistribute it subject to the terms and conditions of the GNU
   11    * Lesser General Public License, as published by the Free Software Foundation.
   12    *
   13    * This program is distributed in the hope that it will be useful,
   14    * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
   15    * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
   16    * for more details.
   17    *
   18    * You should have received a copy of the GNU Lesser General Public License
   19    * along with this distribution; if not, write to:
   20    * Free Software Foundation, Inc.
   21    * 51 Franklin Street, Fifth Floor
   22    * Boston, MA  02110-1301  USA
   23    *
   24    */
   25   package org.hibernate.persister.entity;
   26   
   27   import java.io.Serializable;
   28   import java.util.ArrayList;
   29   import java.util.HashMap;
   30   import java.util.HashSet;
   31   import java.util.Iterator;
   32   import java.util.Map;
   33   
   34   import org.hibernate.EntityMode;
   35   import org.hibernate.HibernateException;
   36   import org.hibernate.MappingException;
   37   import org.hibernate.cache.access.EntityRegionAccessStrategy;
   38   import org.hibernate.engine.Mapping;
   39   import org.hibernate.engine.SessionFactoryImplementor;
   40   import org.hibernate.engine.ExecuteUpdateResultCheckStyle;
   41   import org.hibernate.mapping.Column;
   42   import org.hibernate.mapping.Formula;
   43   import org.hibernate.mapping.Join;
   44   import org.hibernate.mapping.PersistentClass;
   45   import org.hibernate.mapping.Property;
   46   import org.hibernate.mapping.Selectable;
   47   import org.hibernate.mapping.Subclass;
   48   import org.hibernate.mapping.Table;
   49   import org.hibernate.mapping.Value;
   50   import org.hibernate.sql.InFragment;
   51   import org.hibernate.sql.Insert;
   52   import org.hibernate.sql.SelectFragment;
   53   import org.hibernate.type.AssociationType;
   54   import org.hibernate.type.DiscriminatorType;
   55   import org.hibernate.type.Type;
   56   import org.hibernate.util.ArrayHelper;
   57   import org.hibernate.util.MarkerObject;
   58   
   59   /**
   60    * The default implementation of the <tt>EntityPersister</tt> interface.
   61    * Implements the "table-per-class-hierarchy" or "roll-up" mapping strategy
   62    * for an entity class and its inheritence hierarchy.  This is implemented
   63    * as a single table holding all classes in the hierarchy with a discrimator
   64    * column used to determine which concrete class is referenced.
   65    *
   66    * @author Gavin King
   67    */
   68   public class SingleTableEntityPersister extends AbstractEntityPersister {
   69   
   70   	// the class hierarchy structure
   71   	private final int joinSpan;
   72   	private final String[] qualifiedTableNames;
   73   	private final boolean[] isInverseTable;
   74   	private final boolean[] isNullableTable;
   75   	private final String[][] keyColumnNames;
   76   	private final boolean[] cascadeDeleteEnabled;
   77   	private final boolean hasSequentialSelects;
   78   	
   79   	private final String[] spaces;
   80   
   81   	private final String[] subclassClosure;
   82   
   83   	private final String[] subclassTableNameClosure;
   84   	private final boolean[] subclassTableIsLazyClosure;
   85   	private final boolean[] isInverseSubclassTable;
   86   	private final boolean[] isNullableSubclassTable;
   87   	private final boolean[] subclassTableSequentialSelect;
   88   	private final String[][] subclassTableKeyColumnClosure;
   89   	private final boolean[] isClassOrSuperclassTable;
   90   
   91   	// properties of this class, including inherited properties
   92   	private final int[] propertyTableNumbers;
   93   
   94   	// the closure of all columns used by the entire hierarchy including
   95   	// subclasses and superclasses of this class
   96   	private final int[] subclassPropertyTableNumberClosure;
   97   
   98   	private final int[] subclassColumnTableNumberClosure;
   99   	private final int[] subclassFormulaTableNumberClosure;
  100   
  101   	// discriminator column
  102   	private final Map subclassesByDiscriminatorValue = new HashMap();
  103   	private final boolean forceDiscriminator;
  104   	private final String discriminatorColumnName;
  105   	private final String discriminatorFormula;
  106   	private final String discriminatorFormulaTemplate;
  107   	private final String discriminatorAlias;
  108   	private final Type discriminatorType;
  109   	private final String discriminatorSQLValue;
  110   	private final boolean discriminatorInsertable;
  111   
  112   	private final String[] constraintOrderedTableNames;
  113   	private final String[][] constraintOrderedKeyColumnNames;
  114   
  115   	//private final Map propertyTableNumbersByName = new HashMap();
  116   	private final Map propertyTableNumbersByNameAndSubclass = new HashMap();
  117   	
  118   	private final Map sequentialSelectStringsByEntityName = new HashMap();
  119   
  120   	private static final Object NULL_DISCRIMINATOR = new MarkerObject("<null discriminator>");
  121   	private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject("<not null discriminator>");
  122   
  123   	//INITIALIZATION:
  124   
  125   	public SingleTableEntityPersister(
  126   			final PersistentClass persistentClass, 
  127   			final EntityRegionAccessStrategy cacheAccessStrategy,
  128   			final SessionFactoryImplementor factory,
  129   			final Mapping mapping) throws HibernateException {
  130   
  131   		super( persistentClass, cacheAccessStrategy, factory );
  132   
  133   		// CLASS + TABLE
  134   
  135   		joinSpan = persistentClass.getJoinClosureSpan()+1;
  136   		qualifiedTableNames = new String[joinSpan];
  137   		isInverseTable = new boolean[joinSpan];
  138   		isNullableTable = new boolean[joinSpan];
  139   		keyColumnNames = new String[joinSpan][];
  140   		final Table table = persistentClass.getRootTable();
  141   		qualifiedTableNames[0] = table.getQualifiedName( 
  142   				factory.getDialect(), 
  143   				factory.getSettings().getDefaultCatalogName(), 
  144   				factory.getSettings().getDefaultSchemaName() 
  145   		);
  146   		isInverseTable[0] = false;
  147   		isNullableTable[0] = false;
  148   		keyColumnNames[0] = getIdentifierColumnNames();
  149   		cascadeDeleteEnabled = new boolean[joinSpan];
  150   
  151   		// Custom sql
  152   		customSQLInsert = new String[joinSpan];
  153   		customSQLUpdate = new String[joinSpan];
  154   		customSQLDelete = new String[joinSpan];
  155   		insertCallable = new boolean[joinSpan];
  156   		updateCallable = new boolean[joinSpan];
  157   		deleteCallable = new boolean[joinSpan];
  158   		insertResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
  159   		updateResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
  160   		deleteResultCheckStyles = new ExecuteUpdateResultCheckStyle[joinSpan];
  161   
  162   		customSQLInsert[0] = persistentClass.getCustomSQLInsert();
  163   		insertCallable[0] = customSQLInsert[0] != null && persistentClass.isCustomInsertCallable();
  164   		insertResultCheckStyles[0] = persistentClass.getCustomSQLInsertCheckStyle() == null
  165   									  ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[0], insertCallable[0] )
  166   									  : persistentClass.getCustomSQLInsertCheckStyle();
  167   		customSQLUpdate[0] = persistentClass.getCustomSQLUpdate();
  168   		updateCallable[0] = customSQLUpdate[0] != null && persistentClass.isCustomUpdateCallable();
  169   		updateResultCheckStyles[0] = persistentClass.getCustomSQLUpdateCheckStyle() == null
  170   									  ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[0], updateCallable[0] )
  171   									  : persistentClass.getCustomSQLUpdateCheckStyle();
  172   		customSQLDelete[0] = persistentClass.getCustomSQLDelete();
  173   		deleteCallable[0] = customSQLDelete[0] != null && persistentClass.isCustomDeleteCallable();
  174   		deleteResultCheckStyles[0] = persistentClass.getCustomSQLDeleteCheckStyle() == null
  175   									  ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[0], deleteCallable[0] )
  176   									  : persistentClass.getCustomSQLDeleteCheckStyle();
  177   
  178   		// JOINS
  179   
  180   		Iterator joinIter = persistentClass.getJoinClosureIterator();
  181   		int j = 1;
  182   		while ( joinIter.hasNext() ) {
  183   			Join join = (Join) joinIter.next();
  184   			qualifiedTableNames[j] = join.getTable().getQualifiedName( 
  185   					factory.getDialect(), 
  186   					factory.getSettings().getDefaultCatalogName(), 
  187   					factory.getSettings().getDefaultSchemaName() 
  188   			);
  189   			isInverseTable[j] = join.isInverse();
  190   			isNullableTable[j] = join.isOptional();
  191   			cascadeDeleteEnabled[j] = join.getKey().isCascadeDeleteEnabled() && 
  192   				factory.getDialect().supportsCascadeDelete();
  193   
  194   			customSQLInsert[j] = join.getCustomSQLInsert();
  195   			insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
  196   			insertResultCheckStyles[j] = join.getCustomSQLInsertCheckStyle() == null
  197   			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
  198   		                                  : join.getCustomSQLInsertCheckStyle();
  199   			customSQLUpdate[j] = join.getCustomSQLUpdate();
  200   			updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
  201   			updateResultCheckStyles[j] = join.getCustomSQLUpdateCheckStyle() == null
  202   			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
  203   		                                  : join.getCustomSQLUpdateCheckStyle();
  204   			customSQLDelete[j] = join.getCustomSQLDelete();
  205   			deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
  206   			deleteResultCheckStyles[j] = join.getCustomSQLDeleteCheckStyle() == null
  207   			                              ? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
  208   		                                  : join.getCustomSQLDeleteCheckStyle();
  209   
  210   			Iterator iter = join.getKey().getColumnIterator();
  211   			keyColumnNames[j] = new String[ join.getKey().getColumnSpan() ];
  212   			int i = 0;
  213   			while ( iter.hasNext() ) {
  214   				Column col = (Column) iter.next();
  215   				keyColumnNames[j][i++] = col.getQuotedName( factory.getDialect() );
  216   			}
  217   
  218   			j++;
  219   		}
  220   
  221   		constraintOrderedTableNames = new String[qualifiedTableNames.length];
  222   		constraintOrderedKeyColumnNames = new String[qualifiedTableNames.length][];
  223   		for ( int i = qualifiedTableNames.length - 1, position = 0; i >= 0; i--, position++ ) {
  224   			constraintOrderedTableNames[position] = qualifiedTableNames[i];
  225   			constraintOrderedKeyColumnNames[position] = keyColumnNames[i];
  226   		}
  227   
  228   		spaces = ArrayHelper.join(
  229   				qualifiedTableNames, 
  230   				ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
  231   		);
  232   		
  233   		final boolean lazyAvailable = isInstrumented(EntityMode.POJO);
  234   
  235   		boolean hasDeferred = false;
  236   		ArrayList subclassTables = new ArrayList();
  237   		ArrayList joinKeyColumns = new ArrayList();
  238   		ArrayList isConcretes = new ArrayList();
  239   		ArrayList isDeferreds = new ArrayList();
  240   		ArrayList isInverses = new ArrayList();
  241   		ArrayList isNullables = new ArrayList();
  242   		ArrayList isLazies = new ArrayList();
  243   		subclassTables.add( qualifiedTableNames[0] );
  244   		joinKeyColumns.add( getIdentifierColumnNames() );
  245   		isConcretes.add(Boolean.TRUE);
  246   		isDeferreds.add(Boolean.FALSE);
  247   		isInverses.add(Boolean.FALSE);
  248   		isNullables.add(Boolean.FALSE);
  249   		isLazies.add(Boolean.FALSE);
  250   		joinIter = persistentClass.getSubclassJoinClosureIterator();
  251   		while ( joinIter.hasNext() ) {
  252   			Join join = (Join) joinIter.next();
  253   			isConcretes.add( new Boolean( persistentClass.isClassOrSuperclassJoin(join) ) );
  254   			isDeferreds.add( new Boolean( join.isSequentialSelect() ) );
  255   			isInverses.add( new Boolean( join.isInverse() ) );
  256   			isNullables.add( new Boolean( join.isOptional() ) );
  257   			isLazies.add( new Boolean( lazyAvailable && join.isLazy() ) );
  258   			if ( join.isSequentialSelect() && !persistentClass.isClassOrSuperclassJoin(join) ) hasDeferred = true;
  259   			subclassTables.add( join.getTable().getQualifiedName( 
  260   					factory.getDialect(), 
  261   					factory.getSettings().getDefaultCatalogName(), 
  262   					factory.getSettings().getDefaultSchemaName() 
  263   			) );
  264   			Iterator iter = join.getKey().getColumnIterator();
  265   			String[] keyCols = new String[ join.getKey().getColumnSpan() ];
  266   			int i = 0;
  267   			while ( iter.hasNext() ) {
  268   				Column col = (Column) iter.next();
  269   				keyCols[i++] = col.getQuotedName( factory.getDialect() );
  270   			}
  271   			joinKeyColumns.add(keyCols);
  272   		}
  273   		
  274   		subclassTableSequentialSelect = ArrayHelper.toBooleanArray(isDeferreds);
  275   		subclassTableNameClosure = ArrayHelper.toStringArray(subclassTables);
  276   		subclassTableIsLazyClosure = ArrayHelper.toBooleanArray(isLazies);
  277   		subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray(joinKeyColumns);
  278   		isClassOrSuperclassTable = ArrayHelper.toBooleanArray(isConcretes);
  279   		isInverseSubclassTable = ArrayHelper.toBooleanArray(isInverses);
  280   		isNullableSubclassTable = ArrayHelper.toBooleanArray(isNullables);
  281   		hasSequentialSelects = hasDeferred;
  282   
  283   		// DISCRIMINATOR
  284   
  285   		final Object discriminatorValue;
  286   		if ( persistentClass.isPolymorphic() ) {
  287   			Value discrimValue = persistentClass.getDiscriminator();
  288   			if (discrimValue==null) {
  289   				throw new MappingException("discriminator mapping required for single table polymorphic persistence");
  290   			}
  291   			forceDiscriminator = persistentClass.isForceDiscriminator();
  292   			Selectable selectable = (Selectable) discrimValue.getColumnIterator().next();
  293   			if ( discrimValue.hasFormula() ) {
  294   				Formula formula = (Formula) selectable;
  295   				discriminatorFormula = formula.getFormula();
  296   				discriminatorFormulaTemplate = formula.getTemplate( factory.getDialect(), factory.getSqlFunctionRegistry() );
  297   				discriminatorColumnName = null;
  298   				discriminatorAlias = "clazz_";
  299   			}
  300   			else {
  301   				Column column = (Column) selectable;
  302   				discriminatorColumnName = column.getQuotedName( factory.getDialect() );
  303   				discriminatorAlias = column.getAlias( factory.getDialect(), persistentClass.getRootTable() );
  304   				discriminatorFormula = null;
  305   				discriminatorFormulaTemplate = null;
  306   			}
  307   			discriminatorType = persistentClass.getDiscriminator().getType();
  308   			if ( persistentClass.isDiscriminatorValueNull() ) {
  309   				discriminatorValue = NULL_DISCRIMINATOR;
  310   				discriminatorSQLValue = InFragment.NULL;
  311   				discriminatorInsertable = false;
  312   			}
  313   			else if ( persistentClass.isDiscriminatorValueNotNull() ) {
  314   				discriminatorValue = NOT_NULL_DISCRIMINATOR;
  315   				discriminatorSQLValue = InFragment.NOT_NULL;
  316   				discriminatorInsertable = false;
  317   			}
  318   			else {
  319   				discriminatorInsertable = persistentClass.isDiscriminatorInsertable() && !discrimValue.hasFormula();
  320   				try {
  321   					DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
  322   					discriminatorValue = dtype.stringToObject( persistentClass.getDiscriminatorValue() );
  323   					discriminatorSQLValue = dtype.objectToSQLString( discriminatorValue, factory.getDialect() );
  324   				}
  325   				catch (ClassCastException cce) {
  326   					throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
  327   				}
  328   				catch (Exception e) {
  329   					throw new MappingException("Could not format discriminator value to SQL string", e);
  330   				}
  331   			}
  332   		}
  333   		else {
  334   			forceDiscriminator = false;
  335   			discriminatorInsertable = false;
  336   			discriminatorColumnName = null;
  337   			discriminatorAlias = null;
  338   			discriminatorType = null;
  339   			discriminatorValue = null;
  340   			discriminatorSQLValue = null;
  341   			discriminatorFormula = null;
  342   			discriminatorFormulaTemplate = null;
  343   		}
  344   
  345   		// PROPERTIES
  346   
  347   		propertyTableNumbers = new int[ getPropertySpan() ];
  348   		Iterator iter = persistentClass.getPropertyClosureIterator();
  349   		int i=0;
  350   		while( iter.hasNext() ) {
  351   			Property prop = (Property) iter.next();
  352   			propertyTableNumbers[i++] = persistentClass.getJoinNumber(prop);
  353   
  354   		}
  355   
  356   		//TODO: code duplication with JoinedSubclassEntityPersister
  357   		
  358   		ArrayList columnJoinNumbers = new ArrayList();
  359   		ArrayList formulaJoinedNumbers = new ArrayList();
  360   		ArrayList propertyJoinNumbers = new ArrayList();
  361   		
  362   		iter = persistentClass.getSubclassPropertyClosureIterator();
  363   		while ( iter.hasNext() ) {
  364   			Property prop = (Property) iter.next();
  365   			Integer join = new Integer( persistentClass.getJoinNumber(prop) );
  366   			propertyJoinNumbers.add(join);
  367   
  368   			//propertyTableNumbersByName.put( prop.getName(), join );
  369   			propertyTableNumbersByNameAndSubclass.put( 
  370   					prop.getPersistentClass().getEntityName() + '.' + prop.getName(), 
  371   					join 
  372   			);
  373   
  374   			Iterator citer = prop.getColumnIterator();
  375   			while ( citer.hasNext() ) {
  376   				Selectable thing = (Selectable) citer.next();
  377   				if ( thing.isFormula() ) {
  378   					formulaJoinedNumbers.add(join);
  379   				}
  380   				else {
  381   					columnJoinNumbers.add(join);
  382   				}
  383   			}
  384   		}
  385   		subclassColumnTableNumberClosure = ArrayHelper.toIntArray(columnJoinNumbers);
  386   		subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaJoinedNumbers);
  387   		subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propertyJoinNumbers);
  388   
  389   		int subclassSpan = persistentClass.getSubclassSpan() + 1;
  390   		subclassClosure = new String[subclassSpan];
  391   		subclassClosure[0] = getEntityName();
  392   		if ( persistentClass.isPolymorphic() ) {
  393   			subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() );
  394   		}
  395   
  396   		// SUBCLASSES
  397   		if ( persistentClass.isPolymorphic() ) {
  398   			iter = persistentClass.getSubclassIterator();
  399   			int k=1;
  400   			while ( iter.hasNext() ) {
  401   				Subclass sc = (Subclass) iter.next();
  402   				subclassClosure[k++] = sc.getEntityName();
  403   				if ( sc.isDiscriminatorValueNull() ) {
  404   					subclassesByDiscriminatorValue.put( NULL_DISCRIMINATOR, sc.getEntityName() );
  405   				}
  406   				else if ( sc.isDiscriminatorValueNotNull() ) {
  407   					subclassesByDiscriminatorValue.put( NOT_NULL_DISCRIMINATOR, sc.getEntityName() );
  408   				}
  409   				else {
  410   					try {
  411   						DiscriminatorType dtype = (DiscriminatorType) discriminatorType;
  412   						subclassesByDiscriminatorValue.put(
  413   							dtype.stringToObject( sc.getDiscriminatorValue() ),
  414   							sc.getEntityName()
  415   						);
  416   					}
  417   					catch (ClassCastException cce) {
  418   						throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() );
  419   					}
  420   					catch (Exception e) {
  421   						throw new MappingException("Error parsing discriminator value", e);
  422   					}
  423   				}
  424   			}
  425   		}
  426   
  427   		initLockers();
  428   
  429   		initSubclassPropertyAliasesMap(persistentClass);
  430   		
  431   		postConstruct(mapping);
  432   
  433   	}
  434   
  435   	protected boolean isInverseTable(int j) {
  436   		return isInverseTable[j];
  437   	}
  438   
  439   	protected boolean isInverseSubclassTable(int j) {
  440   		return isInverseSubclassTable[j];
  441   	}
  442   
  443   	public String getDiscriminatorColumnName() {
  444   		return discriminatorColumnName;
  445   	}
  446   
  447   	protected String getDiscriminatorAlias() {
  448   		return discriminatorAlias;
  449   	}
  450   
  451   	protected String getDiscriminatorFormulaTemplate() {
  452   		return discriminatorFormulaTemplate;
  453   	}
  454   
  455   	public String getTableName() {
  456   		return qualifiedTableNames[0];
  457   	}
  458   
  459   	public Type getDiscriminatorType() {
  460   		return discriminatorType;
  461   	}
  462   
  463   	public String getDiscriminatorSQLValue() {
  464   		return discriminatorSQLValue;
  465   	}
  466   
  467   	public String[] getSubclassClosure() {
  468   		return subclassClosure;
  469   	}
  470   
  471   	public String getSubclassForDiscriminatorValue(Object value) {
  472   		if (value==null) {
  473   			return (String) subclassesByDiscriminatorValue.get(NULL_DISCRIMINATOR);
  474   		}
  475   		else {
  476   			String result = (String) subclassesByDiscriminatorValue.get(value);
  477   			if (result==null) result = (String) subclassesByDiscriminatorValue.get(NOT_NULL_DISCRIMINATOR);
  478   			return result;
  479   		}
  480   	}
  481   
  482   	public Serializable[] getPropertySpaces() {
  483   		return spaces;
  484   	}
  485   
  486   	//Access cached SQL
  487   
  488   	protected boolean isDiscriminatorFormula() {
  489   		return discriminatorColumnName==null;
  490   	}
  491   
  492   	protected String getDiscriminatorFormula() {
  493   		return discriminatorFormula;
  494   	}
  495   
  496   	protected String getTableName(int j) {
  497   		return qualifiedTableNames[j];
  498   	}
  499   	
  500   	protected String[] getKeyColumns(int j) {
  501   		return keyColumnNames[j];
  502   	}
  503   	
  504   	protected boolean isTableCascadeDeleteEnabled(int j) {
  505   		return cascadeDeleteEnabled[j];
  506   	}
  507   	
  508   	protected boolean isPropertyOfTable(int property, int j) {
  509   		return propertyTableNumbers[property]==j;
  510   	}
  511   
  512   	protected boolean isSubclassTableSequentialSelect(int j) {
  513   		return subclassTableSequentialSelect[j] && !isClassOrSuperclassTable[j];
  514   	}
  515   	
  516   	// Execute the SQL:
  517   
  518   	public String fromTableFragment(String name) {
  519   		return getTableName() + ' ' + name;
  520   	}
  521   
  522   	public String filterFragment(String alias) throws MappingException {
  523   		String result = discriminatorFilterFragment(alias);
  524   		if ( hasWhere() ) result += " and " + getSQLWhereString(alias);
  525   		return result;
  526   	}
  527   	
  528   	public String oneToManyFilterFragment(String alias) throws MappingException {
  529   		return forceDiscriminator ?
  530   			discriminatorFilterFragment(alias) :
  531   			"";
  532   	}
  533   
  534   	private String discriminatorFilterFragment(String alias) throws MappingException {
  535   		if ( needsDiscriminator() ) {
  536   			InFragment frag = new InFragment();
  537   
  538   			if ( isDiscriminatorFormula() ) {
  539   				frag.setFormula( alias, getDiscriminatorFormulaTemplate() );
  540   			}
  541   			else {
  542   				frag.setColumn( alias, getDiscriminatorColumnName() );
  543   			}
  544   
  545   			String[] subclasses = getSubclassClosure();
  546   			for ( int i=0; i<subclasses.length; i++ ) {
  547   				final Queryable queryable = (Queryable) getFactory().getEntityPersister( subclasses[i] );
  548   				if ( !queryable.isAbstract() ) frag.addValue( queryable.getDiscriminatorSQLValue() );
  549   			}
  550   
  551   			StringBuffer buf = new StringBuffer(50)
  552   				.append(" and ")
  553   				.append( frag.toFragmentString() );
  554   
  555   			return buf.toString();
  556   		}
  557   		else {
  558   			return "";
  559   		}
  560   	}
  561   
  562   	private boolean needsDiscriminator() {
  563   		return forceDiscriminator || isInherited();
  564   	}
  565   
  566   	public String getSubclassPropertyTableName(int i) {
  567   		return subclassTableNameClosure[ subclassPropertyTableNumberClosure[i] ];
  568   	}
  569   
  570   	protected void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
  571   		if ( isDiscriminatorFormula() ) {
  572   			select.addFormula( name, getDiscriminatorFormulaTemplate(), getDiscriminatorAlias() );
  573   		}
  574   		else {
  575   			select.addColumn( name, getDiscriminatorColumnName(),  getDiscriminatorAlias() );
  576   		}
  577   	}
  578   	
  579   	protected int[] getPropertyTableNumbersInSelect() {
  580   		return propertyTableNumbers;
  581   	}
  582   
  583   	protected int getSubclassPropertyTableNumber(int i) {
  584   		return subclassPropertyTableNumberClosure[i];
  585   	}
  586   
  587   	public int getTableSpan() {
  588   		return joinSpan;
  589   	}
  590   
  591   	protected void addDiscriminatorToInsert(Insert insert) {
  592   
  593   		if (discriminatorInsertable) {
  594   			insert.addColumn( getDiscriminatorColumnName(), discriminatorSQLValue );
  595   		}
  596   
  597   	}
  598   
  599   	protected int[] getSubclassColumnTableNumberClosure() {
  600   		return subclassColumnTableNumberClosure;
  601   	}
  602   
  603   	protected int[] getSubclassFormulaTableNumberClosure() {
  604   		return subclassFormulaTableNumberClosure;
  605   	}
  606   
  607   	protected int[] getPropertyTableNumbers() {
  608   		return propertyTableNumbers;
  609   	}
  610   		
  611   	protected boolean isSubclassPropertyDeferred(String propertyName, String entityName) {
  612   		return hasSequentialSelects && 
  613   			isSubclassTableSequentialSelect( getSubclassPropertyTableNumber(propertyName, entityName) );
  614   	}
  615   	
  616   	public boolean hasSequentialSelect() {
  617   		return hasSequentialSelects;
  618   	}
  619   	
  620   	private int getSubclassPropertyTableNumber(String propertyName, String entityName) {
  621   		Type type = propertyMapping.toType(propertyName);
  622   		if ( type.isAssociationType() && ( (AssociationType) type ).useLHSPrimaryKey() ) return 0;
  623   		final Integer tabnum = (Integer) propertyTableNumbersByNameAndSubclass.get(entityName + '.' + propertyName);
  624   		return tabnum==null ? 0 : tabnum.intValue();
  625   	}
  626   	
  627   	protected String getSequentialSelect(String entityName) {
  628   		return (String) sequentialSelectStringsByEntityName.get(entityName);
  629   	}
  630   
  631   	private String generateSequentialSelect(Loadable persister) {
  632   		//if ( this==persister || !hasSequentialSelects ) return null;
  633   
  634   		//note that this method could easily be moved up to BasicEntityPersister,
  635   		//if we ever needed to reuse it from other subclasses
  636   		
  637   		//figure out which tables need to be fetched
  638   		AbstractEntityPersister subclassPersister = (AbstractEntityPersister) persister;
  639   		HashSet tableNumbers = new HashSet();
  640   		String[] props = subclassPersister.getPropertyNames();
  641   		String[] classes = subclassPersister.getPropertySubclassNames();
  642   		for ( int i=0; i<props.length; i++ ) {
  643   			int propTableNumber = getSubclassPropertyTableNumber( props[i], classes[i] );
  644   			if ( isSubclassTableSequentialSelect(propTableNumber) && !isSubclassTableLazy(propTableNumber) ) {
  645   				tableNumbers.add( new Integer(propTableNumber) );
  646   			}
  647   		}
  648   		if ( tableNumbers.isEmpty() ) return null;
  649   		
  650   		//figure out which columns are needed
  651   		ArrayList columnNumbers = new ArrayList();
  652   		final int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
  653   		for ( int i=0; i<getSubclassColumnClosure().length; i++ ) {
  654   			if ( tableNumbers.contains( new Integer( columnTableNumbers[i] ) ) ) {
  655   				columnNumbers.add( new Integer(i) );
  656   			}
  657   		}
  658   		
  659   		//figure out which formulas are needed
  660   		ArrayList formulaNumbers = new ArrayList();
  661   		final int[] formulaTableNumbers = getSubclassColumnTableNumberClosure();
  662   		for ( int i=0; i<getSubclassFormulaTemplateClosure().length; i++ ) {
  663   			if ( tableNumbers.contains( new Integer( formulaTableNumbers[i] ) ) ) {
  664   				formulaNumbers.add( new Integer(i) );
  665   			}
  666   		}
  667   		
  668   		//render the SQL
  669   		return renderSelect( 
  670   			ArrayHelper.toIntArray(tableNumbers),
  671   			ArrayHelper.toIntArray(columnNumbers),
  672   			ArrayHelper.toIntArray(formulaNumbers)
  673   		);
  674   	}
  675   		
  676   		
  677   	protected String[] getSubclassTableKeyColumns(int j) {
  678   		return subclassTableKeyColumnClosure[j];
  679   	}
  680   
  681   	public String getSubclassTableName(int j) {
  682   		return subclassTableNameClosure[j];
  683   	}
  684   
  685   	public int getSubclassTableSpan() {
  686   		return subclassTableNameClosure.length;
  687   	}
  688   
  689   	protected boolean isClassOrSuperclassTable(int j) {
  690   		return isClassOrSuperclassTable[j];
  691   	}
  692   
  693   	protected boolean isSubclassTableLazy(int j) {
  694   		return subclassTableIsLazyClosure[j];
  695   	}
  696   	
  697   	protected boolean isNullableTable(int j) {
  698   		return isNullableTable[j];
  699   	}
  700   	
  701   	protected boolean isNullableSubclassTable(int j) {
  702   		return isNullableSubclassTable[j];
  703   	}
  704   
  705   	public String getPropertyTableName(String propertyName) {
  706   		Integer index = getEntityMetamodel().getPropertyIndexOrNull(propertyName);
  707   		if (index==null) return null;
  708   		return qualifiedTableNames[ propertyTableNumbers[ index.intValue() ] ];
  709   	}
  710   	
  711   	public void postInstantiate() {
  712   		super.postInstantiate();
  713   		if (hasSequentialSelects) {
  714   			String[] entityNames = getSubclassClosure();
  715   			for ( int i=1; i<entityNames.length; i++ ) {
  716   				Loadable loadable = (Loadable) getFactory().getEntityPersister( entityNames[i] );
  717   				if ( !loadable.isAbstract() ) { //perhaps not really necessary...
  718   					String sequentialSelect = generateSequentialSelect(loadable);
  719   					sequentialSelectStringsByEntityName.put( entityNames[i], sequentialSelect );
  720   				}
  721   			}
  722   		}
  723   	}
  724   
  725   	public boolean isMultiTable() {
  726   		return getTableSpan() > 1;
  727   	}
  728   
  729   	public String[] getConstraintOrderedTableNameClosure() {
  730   		return constraintOrderedTableNames;
  731   	}
  732   
  733   	public String[][] getContraintOrderedTableKeyColumnClosure() {
  734   		return constraintOrderedKeyColumnNames;
  735   	}
  736   }

Save This Page
Home » hibernate-distribution-3.3.1.GA-dist » org.hibernate » persister » entity » [javadoc | source]