KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > persister > entity > BasicEntityPersister


1 //$Id: BasicEntityPersister.java,v 1.54 2005/07/21 01:11:52 oneovthafew Exp $
2
package org.hibernate.persister.entity;
3
4 import java.io.Serializable JavaDoc;
5 import java.sql.CallableStatement JavaDoc;
6 import java.sql.PreparedStatement JavaDoc;
7 import java.sql.ResultSet JavaDoc;
8 import java.sql.SQLException JavaDoc;
9 import java.sql.Types JavaDoc;
10 import java.util.ArrayList JavaDoc;
11 import java.util.Arrays JavaDoc;
12 import java.util.HashMap JavaDoc;
13 import java.util.HashSet JavaDoc;
14 import java.util.Iterator JavaDoc;
15 import java.util.Map JavaDoc;
16 import java.util.Set JavaDoc;
17
18 import net.sf.cglib.transform.impl.InterceptFieldEnabled;
19
20 import org.apache.commons.logging.Log;
21 import org.apache.commons.logging.LogFactory;
22 import org.hibernate.AssertionFailure;
23 import org.hibernate.EntityMode;
24 import org.hibernate.FetchMode;
25 import org.hibernate.HibernateException;
26 import org.hibernate.LockMode;
27 import org.hibernate.MappingException;
28 import org.hibernate.QueryException;
29 import org.hibernate.StaleObjectStateException;
30 import org.hibernate.cache.CacheConcurrencyStrategy;
31 import org.hibernate.cache.CacheKey;
32 import org.hibernate.cache.entry.CacheEntryStructure;
33 import org.hibernate.cache.entry.StructuredCacheEntry;
34 import org.hibernate.cache.entry.UnstructuredCacheEntry;
35 import org.hibernate.engine.CascadeStyle;
36 import org.hibernate.engine.EntityEntry;
37 import org.hibernate.engine.Mapping;
38 import org.hibernate.engine.SessionFactoryImplementor;
39 import org.hibernate.engine.SessionImplementor;
40 import org.hibernate.engine.Versioning;
41 import org.hibernate.exception.JDBCExceptionHelper;
42 import org.hibernate.id.IdentifierGenerator;
43 import org.hibernate.id.IdentifierGeneratorFactory;
44 import org.hibernate.id.PostInsertIdentifierGenerator;
45 import org.hibernate.id.PostInsertIdentityPersister;
46 import org.hibernate.intercept.FieldInterceptor;
47 import org.hibernate.intercept.LazyPropertyInitializer;
48 import org.hibernate.loader.entity.BatchingEntityLoader;
49 import org.hibernate.loader.entity.EntityLoader;
50 import org.hibernate.loader.entity.UniqueEntityLoader;
51 import org.hibernate.mapping.Column;
52 import org.hibernate.mapping.Component;
53 import org.hibernate.mapping.PersistentClass;
54 import org.hibernate.mapping.Property;
55 import org.hibernate.mapping.Selectable;
56 import org.hibernate.metadata.ClassMetadata;
57 import org.hibernate.pretty.MessageHelper;
58 import org.hibernate.property.BackrefPropertyAccessor;
59 import org.hibernate.sql.Alias;
60 import org.hibernate.sql.Delete;
61 import org.hibernate.sql.Insert;
62 import org.hibernate.sql.JoinFragment;
63 import org.hibernate.sql.Select;
64 import org.hibernate.sql.SelectFragment;
65 import org.hibernate.sql.SimpleSelect;
66 import org.hibernate.sql.Template;
67 import org.hibernate.sql.Update;
68 import org.hibernate.tuple.EntityMetamodel;
69 import org.hibernate.tuple.EntityTuplizer;
70 import org.hibernate.tuple.Tuplizer;
71 import org.hibernate.type.AbstractComponentType;
72 import org.hibernate.type.AssociationType;
73 import org.hibernate.type.EntityType;
74 import org.hibernate.type.Type;
75 import org.hibernate.type.TypeFactory;
76 import org.hibernate.type.VersionType;
77 import org.hibernate.util.ArrayHelper;
78 import org.hibernate.util.CollectionHelper;
79 import org.hibernate.util.FilterHelper;
80 import org.hibernate.util.GetGeneratedKeysHelper;
81 import org.hibernate.util.StringHelper;
82
83 /**
84  * Basic functionality for persisting an entity via JDBC
85  * through either generated or custom SQL
86  *
87  * @author Gavin King
88  */

89 public abstract class BasicEntityPersister
90         implements OuterJoinLoadable, Queryable, ClassMetadata, UniqueKeyLoadable,
91         SQLLoadable, LazyPropertyInitializer, PostInsertIdentityPersister {
92
93     private static final Log log = LogFactory.getLog( BasicEntityPersister.class );
94
95     public static final String JavaDoc ENTITY_CLASS = "class";
96
97     // moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
98
private final SessionFactoryImplementor factory;
99     private final CacheConcurrencyStrategy cache;
100     private final CacheEntryStructure cacheEntryStructure;
101     private final EntityMetamodel entityMetamodel;
102     private final Map JavaDoc entityNameBySubclass = new HashMap JavaDoc();
103     // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104

105     private final String JavaDoc[] rootTableKeyColumnNames;
106     private final String JavaDoc[] identifierAliases;
107     private final int identifierColumnSpan;
108     private final String JavaDoc versionColumnName;
109     private final boolean hasFormulaProperties;
110     private final int batchSize;
111     private final boolean hasSubselectLoadableCollections;
112     protected final String JavaDoc rowIdName;
113
114     private final Set JavaDoc lazyProperties;
115
116     // The optional SQL string defined in the where attribute
117
private final String JavaDoc sqlWhereString;
118     private final String JavaDoc sqlWhereStringTemplate;
119
120     //information about properties of this class,
121
//including inherited properties
122
//(only really needed for updatable/insertable properties)
123
private final int[] propertyColumnSpans;
124     private final String JavaDoc[] propertySubclassNames;
125     private final String JavaDoc[][] propertyColumnAliases;
126     private final String JavaDoc[][] propertyColumnNames;
127     private final String JavaDoc[][] propertyColumnFormulaTemplates;
128     private final boolean[][] propertyColumnUpdateable;
129     private final boolean[][] propertyColumnInsertable;
130     private final boolean[] propertyUniqueness;
131     private final boolean[] propertySelectable;
132
133     //information about lazy properties of this class
134
private final String JavaDoc[] lazyPropertyNames;
135     private final int[] lazyPropertyNumbers;
136     private final Type[] lazyPropertyTypes;
137     private final String JavaDoc[][] lazyPropertyColumnAliases;
138
139     //information about all properties in class hierarchy
140
private final String JavaDoc[] subclassPropertyNameClosure;
141     private final String JavaDoc[] subclassPropertySubclassNameClosure;
142     private final Type[] subclassPropertyTypeClosure;
143     private final String JavaDoc[][] subclassPropertyFormulaTemplateClosure;
144     private final String JavaDoc[][] subclassPropertyColumnNameClosure;
145     private final FetchMode[] subclassPropertyFetchModeClosure;
146     private final boolean[] subclassPropertyNullabilityClosure;
147     private final boolean[] propertyDefinedOnSubclass;
148     private final int[][] subclassPropertyColumnNumberClosure;
149     private final int[][] subclassPropertyFormulaNumberClosure;
150
151     //information about all columns/formulas in class hierarchy
152
private final String JavaDoc[] subclassColumnClosure;
153     private final boolean[] subclassColumnLazyClosure;
154     private final String JavaDoc[] subclassColumnAliasClosure;
155     private final boolean[] subclassColumnSelectableClosure;
156     private final String JavaDoc[] subclassFormulaClosure;
157     private final String JavaDoc[] subclassFormulaTemplateClosure;
158     private final String JavaDoc[] subclassFormulaAliasClosure;
159     private final boolean[] subclassFormulaLazyClosure;
160     
161     // dynamic filters attached to the class-level
162
private final FilterHelper filterHelper;
163
164     private final Map JavaDoc uniqueKeyLoaders = new HashMap JavaDoc();
165     private final Map JavaDoc lockers = new HashMap JavaDoc();
166     private final Map JavaDoc loaders = new HashMap JavaDoc();
167
168     // SQL strings
169
private String JavaDoc sqlVersionSelectString;
170     private String JavaDoc sqlSnapshotSelectString;
171     private String JavaDoc sqlLazySelectString;
172
173     private String JavaDoc sqlIdentityInsertString;
174     private String JavaDoc sqlUpdateByRowIdString;
175     private String JavaDoc sqlLazyUpdateByRowIdString;
176
177     private String JavaDoc[] sqlDeleteStrings;
178     private String JavaDoc[] sqlInsertStrings;
179     private String JavaDoc[] sqlUpdateStrings;
180     private String JavaDoc[] sqlLazyUpdateStrings;
181
182     //Custom SQL (would be better if these were private)
183
protected boolean[] insertCallable;
184     protected boolean[] updateCallable;
185     protected boolean[] deleteCallable;
186     protected String JavaDoc[] customSQLInsert;
187     protected String JavaDoc[] customSQLUpdate;
188     protected String JavaDoc[] customSQLDelete;
189
190     private boolean[] tableHasColumns;
191
192     private final String JavaDoc loaderName;
193
194     private UniqueEntityLoader queryLoader;
195
196     private final String JavaDoc temporaryIdTableName;
197     private final String JavaDoc temporaryIdTableDDL;
198
199     private final Map JavaDoc subclassPropertyAliases = new HashMap JavaDoc();
200     private final Map JavaDoc subclassPropertyColumnNames = new HashMap JavaDoc();
201
202     protected final BasicEntityPropertyMapping propertyMapping;
203
204     protected void addDiscriminatorToInsert(Insert insert) {}
205
206     protected void addDiscriminatorToSelect(SelectFragment select, String JavaDoc name, String JavaDoc suffix) {}
207
208     protected abstract int[] getSubclassColumnTableNumberClosure();
209
210     protected abstract int[] getSubclassFormulaTableNumberClosure();
211
212     public abstract String JavaDoc getSubclassTableName(int j);
213
214     protected abstract String JavaDoc[] getSubclassTableKeyColumns(int j);
215
216     protected abstract boolean isClassOrSuperclassTable(int j);
217
218     protected abstract int getSubclassTableSpan();
219
220     protected abstract int getTableSpan();
221
222     protected abstract boolean isTableCascadeDeleteEnabled(int j);
223
224     protected abstract String JavaDoc getTableName(int j);
225
226     protected abstract String JavaDoc[] getKeyColumns(int j);
227
228     protected abstract boolean isPropertyOfTable(int property, int j);
229
230     protected abstract int[] getPropertyTableNumbersInSelect();
231
232     protected abstract int[] getPropertyTableNumbers();
233
234     protected abstract int getSubclassPropertyTableNumber(int i);
235     
236     protected abstract String JavaDoc filterFragment(String JavaDoc alias) throws MappingException;
237
238     private static final String JavaDoc DISCRIMINATOR_ALIAS = "clazz_";
239     
240     public String JavaDoc getDiscriminatorColumnName() {
241         return DISCRIMINATOR_ALIAS;
242     }
243
244     protected String JavaDoc getDiscriminatorAlias() {
245         return DISCRIMINATOR_ALIAS;
246     }
247
248     protected String JavaDoc getDiscriminatorFormulaTemplate() {
249         return null;
250     }
251
252     protected boolean isInverseTable(int j) {
253         return false;
254     }
255
256     protected boolean isNullableTable(int j) {
257         return false;
258     }
259
260     protected boolean isNullableSubclassTable(int j) {
261         return false;
262     }
263
264     protected boolean isInverseSubclassTable(int j) {
265         return false;
266     }
267     
268     public boolean isSubclassEntityName(String JavaDoc entityName) {
269         return entityMetamodel.getSubclassEntityNames().contains(entityName);
270     }
271
272     private boolean[] getTableHasColumns() {
273         return tableHasColumns;
274     }
275
276     public String JavaDoc[] getRootTableKeyColumnNames() {
277         return rootTableKeyColumnNames;
278     }
279     
280     protected String JavaDoc[] getSQLUpdateByRowIdStrings() {
281         if ( sqlUpdateByRowIdString == null ) {
282             throw new AssertionFailure( "no update by row id" );
283         }
284         String JavaDoc[] result = new String JavaDoc[getTableSpan()];
285         result[0] = sqlUpdateByRowIdString;
286         for ( int i = 1; i < getTableSpan(); i++ ) result[i] = sqlUpdateStrings[i];
287         return result;
288     }
289
290     protected String JavaDoc[] getSQLLazyUpdateByRowIdStrings() {
291         if ( sqlLazyUpdateByRowIdString == null ) {
292             throw new AssertionFailure( "no update by row id" );
293         }
294         String JavaDoc[] result = new String JavaDoc[getTableSpan()];
295         result[0] = sqlLazyUpdateByRowIdString;
296         for ( int i = 1; i < getTableSpan(); i++ ) result[i] = sqlLazyUpdateStrings[i];
297         return result;
298     }
299
300     protected String JavaDoc getSQLSnapshotSelectString() {
301         return sqlSnapshotSelectString;
302     }
303
304     protected String JavaDoc getSQLLazySelectString() {
305         return sqlLazySelectString;
306     }
307
308     protected String JavaDoc[] getSQLDeleteStrings() {
309         return sqlDeleteStrings;
310     }
311
312     protected String JavaDoc[] getSQLInsertStrings() {
313         return sqlInsertStrings;
314     }
315
316     protected String JavaDoc[] getSQLUpdateStrings() {
317         return sqlUpdateStrings;
318     }
319
320     protected String JavaDoc[] getSQLLazyUpdateStrings() {
321         return sqlLazyUpdateStrings;
322     }
323
324     /**
325      * The query that inserts a row, letting the database generate an id
326      */

327     protected String JavaDoc getSQLIdentityInsertString() {
328         return sqlIdentityInsertString;
329     }
330
331     protected String JavaDoc getVersionSelectString() {
332         return sqlVersionSelectString;
333     }
334
335     protected boolean isInsertCallable(int j) {
336         return insertCallable[j];
337     }
338
339     protected boolean isUpdateCallable(int j) {
340         return updateCallable[j];
341     }
342
343     protected boolean isDeleteCallable(int j) {
344         return deleteCallable[j];
345     }
346
347     protected boolean isSubclassPropertyDeferred(String JavaDoc propertyName, String JavaDoc entityName) {
348         return false;
349     }
350
351     protected boolean isSubclassTableSequentialSelect(int j) {
352         return false;
353     }
354
355     public boolean hasSequentialSelect() {
356         return false;
357     }
358
359     /**
360      * Decide which tables need to be updated
361      */

362     protected boolean[] getTableUpdateNeeded(final int[] dirtyProperties, boolean hasDirtyCollection) {
363
364         if ( dirtyProperties == null ) {
365             return getTableHasColumns(); // for objects that came in via update()
366
}
367         else {
368             boolean[] updateability = getPropertyUpdateability();
369             int[] propertyTableNumbers = getPropertyTableNumbers();
370             boolean[] tableUpdateNeeded = new boolean[ getTableSpan() ];
371             for ( int i = 0; i < dirtyProperties.length; i++ ) {
372                 int property = dirtyProperties[i];
373                 int table = propertyTableNumbers[property];
374                 tableUpdateNeeded[table] = tableUpdateNeeded[table] ||
375                         ( getPropertyColumnSpan(property) > 0 && updateability[property] );
376             }
377             if ( isVersioned() ) {
378                 tableUpdateNeeded[0] = tableUpdateNeeded[0] ||
379                     Versioning.isVersionIncrementRequired( dirtyProperties, hasDirtyCollection, getPropertyVersionability() );
380             }
381             return tableUpdateNeeded;
382         }
383     }
384
385     public boolean hasRowId() {
386         return rowIdName != null;
387     }
388
389     public BasicEntityPersister(
390             final PersistentClass persistentClass,
391             final CacheConcurrencyStrategy cache,
392             final SessionFactoryImplementor factory)
393     throws HibernateException {
394
395         // moved up from AbstractEntityPersister ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
396
this.factory = factory;
397         this.cache = cache;
398         this.cacheEntryStructure = factory.getSettings().isStructuredCacheEntriesEnabled() ?
399                 (CacheEntryStructure) new StructuredCacheEntry(this) :
400                 (CacheEntryStructure) new UnstructuredCacheEntry();
401
402         this.entityMetamodel = new EntityMetamodel( persistentClass, factory );
403
404         if ( persistentClass.hasPojoRepresentation() ) {
405             //TODO: this is currently specific to pojos, but need to be available for all entity-modes
406
Iterator JavaDoc iter = persistentClass.getSubclassIterator();
407             while ( iter.hasNext() ) {
408                 PersistentClass pc = ( PersistentClass ) iter.next();
409                 entityNameBySubclass.put( pc.getMappedClass(), pc.getEntityName() );
410             }
411         }
412         // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
413

414         int batch = persistentClass.getBatchSize();
415         if (batch==-1) batch = factory.getSettings().getDefaultBatchFetchSize();
416         batchSize = batch;
417         hasSubselectLoadableCollections = persistentClass.hasSubselectLoadableCollections();
418
419         propertyMapping = new BasicEntityPropertyMapping( this );
420
421         // IDENTIFIER
422

423         identifierColumnSpan = persistentClass.getIdentifier().getColumnSpan();
424         rootTableKeyColumnNames = new String JavaDoc[identifierColumnSpan];
425         identifierAliases = new String JavaDoc[identifierColumnSpan];
426
427         rowIdName = persistentClass.getRootTable().getRowId();
428
429         loaderName = persistentClass.getLoaderName();
430
431         Iterator JavaDoc iter = persistentClass.getIdentifier().getColumnIterator();
432         int i = 0;
433         while ( iter.hasNext() ) {
434             Column col = ( Column ) iter.next();
435             rootTableKeyColumnNames[i] = col.getQuotedName( factory.getDialect() );
436             identifierAliases[i] = col.getAlias( factory.getDialect(), persistentClass.getRootTable() );
437             i++;
438         }
439
440         // VERSION
441

442         if ( persistentClass.isVersioned() ) {
443             versionColumnName = ( ( Column ) persistentClass.getVersion().getColumnIterator().next() ).getQuotedName( factory.getDialect() );
444         }
445         else {
446             versionColumnName = null;
447         }
448
449         //WHERE STRING
450

451         sqlWhereString = persistentClass.getWhere();
452         sqlWhereStringTemplate = sqlWhereString == null ?
453                 null :
454                 Template.renderWhereStringTemplate( sqlWhereString, factory.getDialect() );
455
456         // PROPERTIES
457

458         final boolean lazyAvailable = isInstrumented(EntityMode.POJO);
459
460         int hydrateSpan = entityMetamodel.getPropertySpan();
461         propertyColumnSpans = new int[hydrateSpan];
462         propertySubclassNames = new String JavaDoc[hydrateSpan];
463         propertyColumnAliases = new String JavaDoc[hydrateSpan][];
464         propertyColumnNames = new String JavaDoc[hydrateSpan][];
465         propertyColumnFormulaTemplates = new String JavaDoc[hydrateSpan][];
466         propertyUniqueness = new boolean[hydrateSpan];
467         propertySelectable = new boolean[hydrateSpan];
468         propertyColumnUpdateable = new boolean[hydrateSpan][];
469         propertyColumnInsertable = new boolean[hydrateSpan][];
470         HashSet JavaDoc thisClassProperties = new HashSet JavaDoc();
471
472         lazyProperties = new HashSet JavaDoc();
473         ArrayList JavaDoc lazyNames = new ArrayList JavaDoc();
474         ArrayList JavaDoc lazyNumbers = new ArrayList JavaDoc();
475         ArrayList JavaDoc lazyTypes = new ArrayList JavaDoc();
476         ArrayList JavaDoc lazyColAliases = new ArrayList JavaDoc();
477
478         iter = persistentClass.getPropertyClosureIterator();
479         i = 0;
480         boolean foundFormula = false;
481         while ( iter.hasNext() ) {
482             Property prop = ( Property ) iter.next();
483             thisClassProperties.add( prop );
484
485             int span = prop.getColumnSpan();
486             propertyColumnSpans[i] = span;
487             propertySubclassNames[i] = prop.getPersistentClass().getEntityName();
488             String JavaDoc[] colNames = new String JavaDoc[span];
489             String JavaDoc[] colAliases = new String JavaDoc[span];
490             String JavaDoc[] templates = new String JavaDoc[span];
491             Iterator JavaDoc colIter = prop.getColumnIterator();
492             int k = 0;
493             while ( colIter.hasNext() ) {
494                 Selectable thing = ( Selectable ) colIter.next();
495                 colAliases[k] = thing.getAlias( factory.getDialect() , prop.getValue().getTable() );
496                 if ( thing.isFormula() ) {
497                     foundFormula = true;
498                     templates[k] = thing.getTemplate( factory.getDialect() );
499                 }
500                 else {
501                     colNames[k] = thing.getTemplate( factory.getDialect() );
502                 }
503                 k++;
504             }
505             propertyColumnNames[i] = colNames;
506             propertyColumnFormulaTemplates[i] = templates;
507             propertyColumnAliases[i] = colAliases;
508
509             if ( lazyAvailable && prop.isLazy() ) {
510                 lazyProperties.add( prop.getName() );
511                 lazyNames.add( prop.getName() );
512                 lazyNumbers.add( new Integer JavaDoc( i ) );
513                 lazyTypes.add( prop.getValue().getType() );
514                 lazyColAliases.add( colAliases );
515             }
516             
517             propertyColumnUpdateable[i] = prop.getValue().getColumnUpdateability();
518             propertyColumnInsertable[i] = prop.getValue().getColumnInsertability();
519
520             propertySelectable[i] = prop.isSelectable();
521
522             propertyUniqueness[i] = prop.getValue().isAlternateUniqueKey();
523
524             i++;
525
526         }
527         hasFormulaProperties = foundFormula;
528         lazyPropertyColumnAliases = ArrayHelper.to2DStringArray( lazyColAliases );
529         lazyPropertyNames = ArrayHelper.toStringArray( lazyNames );
530         lazyPropertyNumbers = ArrayHelper.toIntArray( lazyNumbers );
531         lazyPropertyTypes = ArrayHelper.toTypeArray( lazyTypes );
532
533         // SUBCLASS PROPERTY CLOSURE
534

535         ArrayList JavaDoc columns = new ArrayList JavaDoc();
536         ArrayList JavaDoc columnsLazy = new ArrayList JavaDoc();
537         ArrayList JavaDoc aliases = new ArrayList JavaDoc();
538         ArrayList JavaDoc formulas = new ArrayList JavaDoc();
539         ArrayList JavaDoc formulaAliases = new ArrayList JavaDoc();
540         ArrayList JavaDoc formulaTemplates = new ArrayList JavaDoc();
541         ArrayList JavaDoc formulasLazy = new ArrayList JavaDoc();
542         ArrayList JavaDoc types = new ArrayList JavaDoc();
543         ArrayList JavaDoc names = new ArrayList JavaDoc();
544         ArrayList JavaDoc classes = new ArrayList JavaDoc();
545         ArrayList JavaDoc templates = new ArrayList JavaDoc();
546         ArrayList JavaDoc propColumns = new ArrayList JavaDoc();
547         ArrayList JavaDoc joinedFetchesList = new ArrayList JavaDoc();
548         ArrayList JavaDoc definedBySubclass = new ArrayList JavaDoc();
549         ArrayList JavaDoc propColumnNumbers = new ArrayList JavaDoc();
550         ArrayList JavaDoc propFormulaNumbers = new ArrayList JavaDoc();
551         ArrayList JavaDoc columnSelectables = new ArrayList JavaDoc();
552         ArrayList JavaDoc propNullables = new ArrayList JavaDoc();
553
554         iter = persistentClass.getSubclassPropertyClosureIterator();
555         while ( iter.hasNext() ) {
556             Property prop = ( Property ) iter.next();
557             names.add( prop.getName() );
558             classes.add( prop.getPersistentClass().getEntityName() );
559             boolean isDefinedBySubclass = !thisClassProperties.contains( prop );
560             definedBySubclass.add( new Boolean JavaDoc(isDefinedBySubclass) );
561             propNullables.add( new Boolean JavaDoc( prop.isOptional() || isDefinedBySubclass) ); //TODO: is this completely correct?
562
types.add( prop.getType() );
563
564             Iterator JavaDoc colIter = prop.getColumnIterator();
565             String JavaDoc[] cols = new String JavaDoc[prop.getColumnSpan()];
566             String JavaDoc[] forms = new String JavaDoc[prop.getColumnSpan()];
567             int[] colnos = new int[prop.getColumnSpan()];
568             int[] formnos = new int[prop.getColumnSpan()];
569             int l = 0;
570             Boolean JavaDoc lazy = new Boolean JavaDoc( prop.isLazy() && lazyAvailable );
571             while ( colIter.hasNext() ) {
572                 Selectable thing = ( Selectable ) colIter.next();
573                 if ( thing.isFormula() ) {
574                     String JavaDoc template = thing.getTemplate( factory.getDialect() );
575                     formnos[l] = formulaTemplates.size();
576                     colnos[l] = -1;
577                     formulaTemplates.add( template );
578                     forms[l] = template;
579                     formulas.add( thing.getText( factory.getDialect() ) );
580                     formulaAliases.add( thing.getAlias( factory.getDialect() ) );
581                     formulasLazy.add( lazy );
582                 }
583                 else {
584                     String JavaDoc colName = thing.getTemplate( factory.getDialect() );
585                     colnos[l] = columns.size(); //before add :-)
586
formnos[l] = -1;
587                     columns.add( colName );
588                     cols[l] = colName;
589                     aliases.add( thing.getAlias( factory.getDialect(), prop.getValue().getTable() ) );
590                     columnsLazy.add( lazy );
591                     columnSelectables.add( new Boolean JavaDoc( prop.isSelectable() ) );
592                 }
593                 l++;
594             }
595             propColumns.add( cols );
596             templates.add( forms );
597             propColumnNumbers.add( colnos );
598             propFormulaNumbers.add( formnos );
599
600             joinedFetchesList.add( prop.getValue().getFetchMode() );
601         }
602         subclassColumnClosure = ArrayHelper.toStringArray( columns );
603         subclassColumnAliasClosure = ArrayHelper.toStringArray( aliases );
604         subclassColumnLazyClosure = ArrayHelper.toBooleanArray( columnsLazy );
605         subclassColumnSelectableClosure = ArrayHelper.toBooleanArray( columnSelectables );
606
607         subclassFormulaClosure = ArrayHelper.toStringArray( formulas );
608         subclassFormulaTemplateClosure = ArrayHelper.toStringArray( formulaTemplates );
609         subclassFormulaAliasClosure = ArrayHelper.toStringArray( formulaAliases );
610         subclassFormulaLazyClosure = ArrayHelper.toBooleanArray( formulasLazy );
611
612         subclassPropertyNameClosure = ArrayHelper.toStringArray( names );
613         subclassPropertySubclassNameClosure = ArrayHelper.toStringArray( classes );
614         subclassPropertyTypeClosure = ArrayHelper.toTypeArray( types );
615         subclassPropertyNullabilityClosure = ArrayHelper.toBooleanArray( propNullables );
616         subclassPropertyFormulaTemplateClosure = ArrayHelper.to2DStringArray( templates );
617         subclassPropertyColumnNameClosure = ArrayHelper.to2DStringArray( propColumns );
618         subclassPropertyColumnNumberClosure = ArrayHelper.to2DIntArray( propColumnNumbers );
619         subclassPropertyFormulaNumberClosure = ArrayHelper.to2DIntArray( propFormulaNumbers );
620
621         subclassPropertyFetchModeClosure = new FetchMode[joinedFetchesList.size()];
622         iter = joinedFetchesList.iterator();
623         int j = 0;
624         while ( iter.hasNext() ) subclassPropertyFetchModeClosure[j++] = ( FetchMode ) iter.next();
625
626         propertyDefinedOnSubclass = new boolean[definedBySubclass.size()];
627         iter = definedBySubclass.iterator();
628         j = 0;
629         while ( iter.hasNext() ) propertyDefinedOnSubclass[j++] = ( ( Boolean JavaDoc ) iter.next() ).booleanValue();
630
631         // Handle any filters applied to the class level
632
filterHelper = new FilterHelper( persistentClass.getFilterMap(), factory.getDialect() );
633
634         temporaryIdTableName = persistentClass.getTemporaryIdTableName();
635         temporaryIdTableDDL = persistentClass.getTemporaryIdTableDDL();
636     }
637
638     protected String JavaDoc generateLazySelectString() {
639
640         if ( !entityMetamodel.hasLazyProperties() ) return null;
641
642         HashSet JavaDoc tableNumbers = new HashSet JavaDoc();
643         ArrayList JavaDoc columnNumbers = new ArrayList JavaDoc();
644         ArrayList JavaDoc formulaNumbers = new ArrayList JavaDoc();
645         for ( int i = 0; i < lazyPropertyNames.length; i++ ) {
646             // all this only really needs to consider properties
647
// of this class, not its subclasses, but since we
648
// are reusing code used for sequential selects, we
649
// use the subclass closure
650
int propertyNumber = getSubclassPropertyIndex( lazyPropertyNames[i] );
651
652             int tableNumber = getSubclassPropertyTableNumber( propertyNumber );
653             tableNumbers.add( new Integer JavaDoc( tableNumber ) );
654
655             int[] colNumbers = subclassPropertyColumnNumberClosure[propertyNumber];
656             for ( int j = 0; j < colNumbers.length; j++ ) {
657                 if ( colNumbers[j]!=-1 ) {
658                     columnNumbers.add( new Integer JavaDoc( colNumbers[j] ) );
659                 }
660             }
661             int[] formNumbers = subclassPropertyFormulaNumberClosure[propertyNumber];
662             for ( int j = 0; j < formNumbers.length; j++ ) {
663                 if ( formNumbers[j]!=-1 ) {
664                     formulaNumbers.add( new Integer JavaDoc( formNumbers[j] ) );
665                 }
666             }
667         }
668         
669         if ( columnNumbers.size()==0 && formulaNumbers.size()==0 ) {
670             // only one-to-one is lazy fetched
671
return null;
672         }
673
674         return renderSelect( ArrayHelper.toIntArray( tableNumbers ),
675                 ArrayHelper.toIntArray( columnNumbers ),
676                 ArrayHelper.toIntArray( formulaNumbers ) );
677
678     }
679
680     public Object JavaDoc initializeLazyProperty(String JavaDoc fieldName, Object JavaDoc entity, SessionImplementor session)
681             throws HibernateException {
682
683         final Serializable JavaDoc id = session.getContextEntityIdentifier( entity );
684
685         final EntityEntry entry = session.getPersistenceContext().getEntry( entity );
686         if ( entry == null ) throw new HibernateException( "entity is not associated with the session: " + id );
687
688         if ( log.isTraceEnabled() ) {
689             log.trace( "initializing lazy properties of: " +
690                     MessageHelper.infoString( this, id, getFactory() ) +
691                     ", field access: " + fieldName );
692         }
693
694         try {
695
696             Object JavaDoc result = null;
697             PreparedStatement JavaDoc ps = null;
698             ResultSet JavaDoc rs = null;
699             try {
700                 final String JavaDoc lazySelect = getSQLLazySelectString();
701                 if (lazySelect!=null) {
702                     // null sql means the lazy properties do not map to
703
// columns or formulas (eg. one-to-one associations)
704
ps = session.getBatcher().prepareSelectStatement(lazySelect);
705                     getIdentifierType().nullSafeSet( ps, id, 1, session );
706                     rs = ps.executeQuery();
707                     rs.next();
708                 }
709                 final Object JavaDoc[] snapshot = entry.getLoadedState();
710                 for ( int j = 0; j < lazyPropertyNames.length; j++ ) {
711                     Object JavaDoc propValue = lazyPropertyTypes[j].nullSafeGet( rs, lazyPropertyColumnAliases[j], session, entity );
712                     setPropertyValue( entity, lazyPropertyNumbers[j], propValue, session.getEntityMode() );
713                     snapshot[ lazyPropertyNumbers[j] ] = lazyPropertyTypes[j].deepCopy( propValue, session.getEntityMode(), factory );
714                     if ( fieldName.equals( lazyPropertyNames[j] ) ) result = propValue;
715                 }
716                 if (rs!=null) rs.close();
717             }
718             finally {
719                 if (ps!=null) session.getBatcher().closeStatement(ps);
720             }
721
722             log.trace( "done initializing lazy properties" );
723
724             return result;
725
726         }
727         catch ( SQLException JavaDoc sqle ) {
728             throw JDBCExceptionHelper.convert(
729                     getFactory().getSQLExceptionConverter(),
730                     sqle,
731                     "could not initialize lazy properties: " +
732                     MessageHelper.infoString( this, id, getFactory() ),
733                     getSQLLazySelectString()
734                 );
735         }
736
737     }
738
739     public boolean isBatchable() {
740         return optimisticLockMode()==Versioning.OPTIMISTIC_LOCK_NONE ||
741             ( !isVersioned() && optimisticLockMode()==Versioning.OPTIMISTIC_LOCK_VERSION ) ||
742             getFactory().getSettings().isJdbcBatchVersionedData();
743     }
744
745     public Serializable JavaDoc[] getQuerySpaces() {
746         return getPropertySpaces();
747     }
748
749     protected Set JavaDoc getLazyProperties() {
750         return lazyProperties;
751     }
752
753     private String JavaDoc getLockString(LockMode lockMode) {
754         return ( String JavaDoc ) lockers.get( lockMode );
755     }
756
757     public boolean isBatchLoadable() {
758         return batchSize > 1;
759     }
760
761     public String JavaDoc[] getIdentifierColumnNames() {
762         return rootTableKeyColumnNames;
763     }
764
765     protected int getIdentifierColumnSpan() {
766         return identifierColumnSpan;
767     }
768
769     protected String JavaDoc[] getIdentifierAliases() {
770         return identifierAliases;
771     }
772
773     public String JavaDoc getVersionColumnName() {
774         return versionColumnName;
775     }
776
777     protected String JavaDoc getVersionedTableName() {
778         return getTableName( 0 );
779     }
780
781     protected boolean[] getSubclassColumnLazyiness() {
782         return subclassColumnLazyClosure;
783     }
784
785     protected boolean[] getSubclassFormulaLazyiness() {
786         return subclassFormulaLazyClosure;
787     }
788     
789     /**
790      * We can't immediately add to the cache if we have formulas
791      * which must be evaluated, or if we have the possibility of
792      * two concurrent updates to the same item being merged on
793      * the database. This can happen if (a) the item is not
794      * versioned and either (b) we have dynamic update enabled
795      * or (c) we have multiple tables holding the state of the
796      * item.
797      */

798     public boolean isCacheInvalidationRequired() {
799         return hasFormulaProperties() ||
800                 ( !isVersioned() && ( entityMetamodel.isDynamicUpdate() || getTableSpan() > 1 ) );
801     }
802
803     public String JavaDoc selectFragment(String JavaDoc alias, String JavaDoc suffix) {
804         return identifierSelectFragment( alias, suffix ) +
805                 propertySelectFragment( alias, suffix, false );
806     }
807
808     public String JavaDoc[] getIdentifierAliases(String JavaDoc suffix) {
809         // NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
810
// was toUnqotedAliasStrings( getIdentiferColumnNames() ) before - now tried
811
// to remove that unqoting and missing aliases..
812
return new Alias( suffix ).toAliasStrings( getIdentifierAliases() );
813     }
814
815     public String JavaDoc[] getPropertyAliases(String JavaDoc suffix, int i) {
816         // NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
817
return new Alias( suffix ).toUnquotedAliasStrings( propertyColumnAliases[i] );
818     }
819
820     public String JavaDoc getDiscriminatorAlias(String JavaDoc suffix) {
821         // NOTE: this assumes something about how propertySelectFragment is implemented by the subclass!
822
// was toUnqotedAliasStrings( getdiscriminatorColumnName() ) before - now tried
823
// to remove that unqoting and missing aliases..
824
return entityMetamodel.hasSubclasses() ?
825                 new Alias( suffix ).toAliasString( getDiscriminatorAlias() ) :
826                 null;
827     }
828
829     public String JavaDoc identifierSelectFragment(String JavaDoc name, String JavaDoc suffix) {
830         return new SelectFragment()
831                 .setSuffix( suffix )
832                 .addColumns( name, getIdentifierColumnNames(), getIdentifierAliases() )
833                 .toFragmentString()
834                 .substring( 2 ); //strip leading ", "
835
}
836
837
838     public String JavaDoc propertySelectFragment(String JavaDoc name, String JavaDoc suffix, boolean allProperties) {
839
840         SelectFragment select = new SelectFragment()
841                 .setSuffix( suffix )
842                 .setUsedAliases( getIdentifierAliases() );
843
844         int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
845         String JavaDoc[] columnAliases = getSubclassColumnAliasClosure();
846         String JavaDoc[] columns = getSubclassColumnClosure();
847         for ( int i = 0; i < getSubclassColumnClosure().length; i++ ) {
848             boolean selectable = ( allProperties || !subclassColumnLazyClosure[i] ) &&
849                 !isSubclassTableSequentialSelect( columnTableNumbers[i] ) &&
850                 subclassColumnSelectableClosure[i];
851             if ( selectable ) {
852                 String JavaDoc subalias = generateTableAlias( name, columnTableNumbers[i] );
853                 select.addColumn( subalias, columns[i], columnAliases[i] );
854             }
855         }
856
857         int[] formulaTableNumbers = getSubclassFormulaTableNumberClosure();
858         String JavaDoc[] formulaTemplates = getSubclassFormulaTemplateClosure();
859         String JavaDoc[] formulaAliases = getSubclassFormulaAliasClosure();
860         for ( int i = 0; i < getSubclassFormulaTemplateClosure().length; i++ ) {
861             boolean selectable = ( allProperties || !subclassFormulaLazyClosure[i] )
862                 && !isSubclassTableSequentialSelect( formulaTableNumbers[i] );
863             if ( selectable ) {
864                 String JavaDoc subalias = generateTableAlias( name, formulaTableNumbers[i] );
865                 select.addFormula( subalias, formulaTemplates[i], formulaAliases[i] );
866             }
867         }
868
869         if ( entityMetamodel.hasSubclasses() ) addDiscriminatorToSelect( select, name, suffix );
870
871         if ( hasRowId() ) select.addColumn( name, rowIdName, ROWID_ALIAS );
872
873         return select.toFragmentString();
874     }
875
876     public Object JavaDoc[] getDatabaseSnapshot(Serializable JavaDoc id, SessionImplementor session)
877             throws HibernateException {
878
879         if ( log.isTraceEnabled() ) {
880             log.trace( "Getting current persistent state for: " + MessageHelper.infoString( this, id, getFactory() ) );
881         }
882
883         try {
884             PreparedStatement JavaDoc ps = session.getBatcher().prepareSelectStatement( getSQLSnapshotSelectString() );
885             try {
886                 getIdentifierType().nullSafeSet( ps, id, 1, session );
887                 //if ( isVersioned() ) getVersionType().nullSafeSet( ps, version, getIdentifierColumnSpan()+1, session );
888
ResultSet JavaDoc rs = ps.executeQuery();
889                 try {
890                     //if there is no resulting row, return null
891
if ( !rs.next() ) return null;
892                     
893                     //otherwise return the "hydrated" state (ie. associations are not resolved)
894
Type[] types = getPropertyTypes();
895                     Object JavaDoc[] values = new Object JavaDoc[types.length];
896                     boolean[] includeProperty = getPropertyUpdateability();
897                     for ( int i = 0; i < types.length; i++ ) {
898                         if ( includeProperty[i] ) {
899                             values[i] = types[i].hydrate( rs, getPropertyAliases( "", i ), session, null ); //null owner ok??
900
}
901                     }
902                     return values;
903                 }
904                 finally {
905                     rs.close();
906                 }
907             }
908             finally {
909                 session.getBatcher().closeStatement( ps );
910             }
911         }
912         catch ( SQLException JavaDoc sqle ) {
913             throw JDBCExceptionHelper.convert(
914                     getFactory().getSQLExceptionConverter(),
915                     sqle,
916                     "could not retrieve snapshot: " +
917                     MessageHelper.infoString( this, id, getFactory() ),
918                     getSQLSnapshotSelectString()
919                 );
920         }
921
922     }
923
924     /**
925      * Generate the SQL that selects the version number by id
926      */

927     protected String JavaDoc generateSelectVersionString() {
928         SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
929                 .setTableName( getVersionedTableName() );
930         if ( isVersioned() ) {
931             select.addColumn( versionColumnName );
932         }
933         else {
934             select.addColumns( rootTableKeyColumnNames );
935         }
936         if ( getFactory().getSettings().isCommentsEnabled() ) {
937             select.setComment( "get version " + getEntityName() );
938         }
939         return select.addCondition( rootTableKeyColumnNames, "=?" ).toStatementString();
940     }
941
942     protected String JavaDoc concretePropertySelectFragment(String JavaDoc alias, boolean[] includeProperty) {
943         int propertyCount = getPropertyNames().length;
944         int[] propertyTableNumbers = getPropertyTableNumbersInSelect();
945         SelectFragment frag = new SelectFragment();
946         for ( int i = 0; i < propertyCount; i++ ) {
947             if ( includeProperty[i] ) { //ie. updateable, not a formula
948
frag.addColumns(
949                         generateTableAlias( alias, propertyTableNumbers[i] ),
950                         propertyColumnNames[i],
951                         propertyColumnAliases[i]
952                     );
953                 frag.addFormulas(
954                         generateTableAlias( alias, propertyTableNumbers[i] ),
955                         propertyColumnFormulaTemplates[i],
956                         propertyColumnAliases[i]
957                     );
958             }
959         }
960         return frag.toFragmentString();
961     }
962
963     protected String JavaDoc generateSnapshotSelectString() {
964
965         //TODO: should we use SELECT .. FOR UPDATE?
966

967         Select select = new Select( getFactory().getDialect() );
968         
969         if ( getFactory().getSettings().isCommentsEnabled() ) {
970             select.setComment( "get current state " + getEntityName() );
971         }
972         
973         String JavaDoc[] aliasedIdColumns = StringHelper.qualify( getRootAlias(), getIdentifierColumnNames() );
974         String JavaDoc selectClause = StringHelper.join( ", ", aliasedIdColumns ) +
975                 concretePropertySelectFragment( getRootAlias(), getPropertyUpdateability() );
976         
977         String JavaDoc fromClause = fromTableFragment( getRootAlias() ) +
978                 fromJoinFragment( getRootAlias(), true, false );
979         
980         String JavaDoc whereClause = new StringBuffer JavaDoc()
981             .append( StringHelper.join( "=? and ",
982                     aliasedIdColumns ) )
983             .append( "=?" )
984             .append( whereJoinFragment( getRootAlias(), true, false ) )
985             .toString();
986
987         /*if ( isVersioned() ) {
988             where.append(" and ")
989                 .append( getVersionColumnName() )
990                 .append("=?");
991         }*/

992
993         return select.setSelectClause( selectClause )
994                 .setFromClause( fromClause )
995                 .setOuterJoins( "", "" )
996                 .setWhereClause( whereClause )
997                 .toStatementString();
998     }
999
1000    /**
1001     * Do a version check
1002     */

1003    public void lock(Serializable JavaDoc id, Object JavaDoc version, Object JavaDoc object, LockMode lockMode, SessionImplementor session)
1004    throws HibernateException {
1005
1006        if ( lockMode != LockMode.NONE ) {
1007
1008            if ( log.isTraceEnabled() ) {
1009                log.trace( "Locking entity: " + MessageHelper.infoString( this, id, getFactory() ) );
1010                if ( isVersioned() ) log.trace( "Version: " + version );
1011            }
1012
1013            final String JavaDoc sql = getLockString( lockMode );
1014
1015            try {
1016
1017                PreparedStatement JavaDoc st = session.getBatcher().prepareSelectStatement( sql );
1018                try {
1019                    getIdentifierType().nullSafeSet( st, id, 1, session );
1020                    if ( isVersioned() ) {
1021                        getVersionType().nullSafeSet( st, version, getIdentifierColumnSpan() + 1, session );
1022                    }
1023
1024                    ResultSet JavaDoc rs = st.executeQuery();
1025                    try {
1026                        if ( !rs.next() ) {
1027                            throw new StaleObjectStateException( getEntityName(), id );
1028                        }
1029                    }
1030                    finally {
1031                        rs.close();
1032                    }
1033                }
1034                finally {
1035                    session.getBatcher().closeStatement( st );
1036                }
1037
1038            }
1039            catch ( SQLException JavaDoc sqle ) {
1040                throw JDBCExceptionHelper.convert(
1041                        getFactory().getSQLExceptionConverter(),
1042                        sqle,
1043                        "could not lock: " +
1044                        MessageHelper.infoString( this, id, getFactory() ),
1045                        sql
1046                    );
1047            }
1048
1049        }
1050
1051    }
1052
1053    /**
1054     * Retrieve the version number
1055     */

1056    public Object JavaDoc getCurrentVersion(Serializable JavaDoc id, SessionImplementor session) throws HibernateException {
1057
1058        if ( log.isTraceEnabled() ) {
1059            log.trace( "Getting version: " + MessageHelper.infoString( this, id, getFactory() ) );
1060        }
1061
1062        try {
1063
1064            PreparedStatement JavaDoc st = session.getBatcher().prepareSelectStatement( getVersionSelectString() );
1065            try {
1066                getIdentifierType().nullSafeSet( st, id, 1, session );
1067
1068                ResultSet JavaDoc rs = st.executeQuery();
1069                try {
1070                    if ( !rs.next() ) return null;
1071                    if ( !isVersioned() ) return this;
1072                    return getVersionType().nullSafeGet( rs, getVersionColumnName(), session, null );
1073                }
1074                finally {
1075                    rs.close();
1076                }
1077            }
1078            finally {
1079                session.getBatcher().closeStatement( st );
1080            }
1081
1082        }
1083        catch ( SQLException JavaDoc sqle ) {
1084            throw JDBCExceptionHelper.convert(
1085                    getFactory().getSQLExceptionConverter(),
1086                    sqle,
1087                    "could not retrieve version: " +
1088                    MessageHelper.infoString( this, id, getFactory() ),
1089                    getVersionSelectString()
1090                );
1091        }
1092
1093    }
1094
1095    /**
1096     * Generate the SQL that pessimistic locks a row by id (and version)
1097     */

1098    protected String JavaDoc generateLockString(LockMode lockMode) {
1099
1100        SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
1101                .setLockMode( lockMode )
1102                .setTableName( getVersionedTableName() )
1103                .addColumn( rootTableKeyColumnNames[0] )
1104                .addCondition( rootTableKeyColumnNames, "=?" );
1105        if ( isVersioned() ) {
1106            select.addWhereToken( "and" )
1107                    .addCondition( getVersionColumnName(), "=?" );
1108        }
1109        if ( getFactory().getSettings().isCommentsEnabled() ) {
1110            select.setComment( "lock " + getEntityName() );
1111        }
1112        return select.toStatementString();
1113
1114    }
1115
1116    protected void initLockers() {
1117        lockers.put( LockMode.READ, generateLockString( LockMode.READ ) );
1118        lockers.put( LockMode.UPGRADE, generateLockString( LockMode.UPGRADE ) );
1119        lockers.put( LockMode.UPGRADE_NOWAIT, generateLockString( LockMode.UPGRADE_NOWAIT ) );
1120    }
1121
1122    public String JavaDoc[] toColumns(String JavaDoc alias, String JavaDoc propertyName) throws QueryException {
1123        return propertyMapping.toColumns( alias, propertyName );
1124    }
1125
1126    public String JavaDoc[] toColumns(String JavaDoc propertyName) throws QueryException {
1127        return propertyMapping.getColumnNames( propertyName );
1128    }
1129
1130    public Type toType(String JavaDoc propertyName) throws QueryException {
1131        return propertyMapping.toType( propertyName );
1132    }
1133
1134    public String JavaDoc[] getPropertyColumnNames(String JavaDoc propertyName) {
1135        return propertyMapping.getColumnNames( propertyName );
1136    }
1137
1138    /**
1139     * Warning:
1140     * When there are duplicated property names in the subclasses
1141     * of the class, this method may return the wrong table
1142     * number for the duplicated subclass property (note that
1143     * SingleTableEntityPersister defines an overloaded form
1144     * which takes the entity name.
1145     */

1146    public int getSubclassPropertyTableNumber(String JavaDoc propertyName) {
1147        final String JavaDoc rootPropertyName = StringHelper.root(propertyName);
1148        Type type = propertyMapping.toType(rootPropertyName);
1149        if ( type.isAssociationType() && ( (AssociationType) type ).useLHSPrimaryKey() ) {
1150            return 0;
1151        }
1152        if ( type.isComponentType() && !propertyName.equals(rootPropertyName) ) {
1153            String JavaDoc unrooted = StringHelper.unroot(propertyName);
1154            int idx = ArrayHelper.indexOf( getSubclassColumnClosure(), unrooted );
1155            if ( idx != -1 ) {
1156                return getSubclassColumnTableNumberClosure()[idx];
1157            }
1158        }
1159        int index = ArrayHelper.indexOf( getSubclassPropertyNameClosure(), rootPropertyName); //TODO: optimize this better!
1160
return index==-1 ? 0 : getSubclassPropertyTableNumber(index);
1161    }
1162
1163    protected String JavaDoc generateTableAlias(String JavaDoc rootAlias, int tableNumber) {
1164        if ( tableNumber == 0 ) return rootAlias;
1165        StringBuffer JavaDoc buf = new StringBuffer JavaDoc().append( rootAlias );
1166        if ( !rootAlias.endsWith( "_" ) ) buf.append( '_' );
1167        return buf.append( tableNumber ).append( '_' ).toString();
1168    }
1169
1170    public String JavaDoc[] toColumns(String JavaDoc name, final int i) {
1171        final String JavaDoc alias = generateTableAlias( name, getSubclassPropertyTableNumber( i ) );
1172        String JavaDoc[] cols = getSubclassPropertyColumnNames( i );
1173        String JavaDoc[] templates = getSubclassPropertyFormulaTemplateClosure()[i];
1174        String JavaDoc[] result = new String JavaDoc[cols.length];
1175        for ( int j = 0; j < cols.length; j++ ) {
1176            if ( cols[j] == null ) {
1177                result[j] = StringHelper.replace( templates[j], Template.TEMPLATE, alias );
1178            }
1179            else {
1180                result[j] = StringHelper.qualify( alias, cols[j] );
1181            }
1182        }
1183        return result;
1184    }
1185
1186    private int getSubclassPropertyIndex(String JavaDoc propertyName) {
1187        return ArrayHelper.indexOf(subclassPropertyNameClosure, propertyName);
1188    }
1189    
1190    protected String JavaDoc[] getPropertySubclassNames() {
1191        return propertySubclassNames;
1192    }
1193
1194    public String JavaDoc[] getPropertyColumnNames(int i) {
1195        return propertyColumnNames[i];
1196    }
1197
1198    protected int getPropertyColumnSpan(int i) {
1199        return propertyColumnSpans[i];
1200    }
1201
1202    protected boolean hasFormulaProperties() {
1203        return hasFormulaProperties;
1204    }
1205
1206    public FetchMode getFetchMode(int i) {
1207        return subclassPropertyFetchModeClosure[i];
1208    }
1209
1210    public Type getSubclassPropertyType(int i) {
1211        return subclassPropertyTypeClosure[i];
1212    }
1213
1214    public String JavaDoc getSubclassPropertyName(int i) {
1215        return subclassPropertyNameClosure[i];
1216    }
1217
1218    public int countSubclassProperties() {
1219        return subclassPropertyTypeClosure.length;
1220    }
1221
1222    public String JavaDoc[] getSubclassPropertyColumnNames(int i) {
1223        return subclassPropertyColumnNameClosure[i];
1224    }
1225
1226    public boolean isDefinedOnSubclass(int i) {
1227        return propertyDefinedOnSubclass[i];
1228    }
1229
1230    protected String JavaDoc[][] getSubclassPropertyFormulaTemplateClosure() {
1231        return subclassPropertyFormulaTemplateClosure;
1232    }
1233
1234    protected Type[] getSubclassPropertyTypeClosure() {
1235        return subclassPropertyTypeClosure;
1236    }
1237
1238    protected String JavaDoc[][] getSubclassPropertyColumnNameClosure() {
1239        return subclassPropertyColumnNameClosure;
1240    }
1241
1242    protected String JavaDoc[] getSubclassPropertyNameClosure() {
1243        return subclassPropertyNameClosure;
1244    }
1245
1246    protected String JavaDoc[] getSubclassPropertySubclassNameClosure() {
1247        return subclassPropertySubclassNameClosure;
1248    }
1249
1250    protected String JavaDoc[] getSubclassColumnClosure() {
1251        return subclassColumnClosure;
1252    }
1253
1254    protected String JavaDoc[] getSubclassColumnAliasClosure() {
1255        return subclassColumnAliasClosure;
1256    }
1257
1258    protected String JavaDoc[] getSubclassFormulaClosure() {
1259        return subclassFormulaClosure;
1260    }
1261
1262    protected String JavaDoc[] getSubclassFormulaTemplateClosure() {
1263        return subclassFormulaTemplateClosure;
1264    }
1265
1266    protected String JavaDoc[] getSubclassFormulaAliasClosure() {
1267        return subclassFormulaAliasClosure;
1268    }
1269
1270    public String JavaDoc[] getSubclassPropertyColumnAliases(String JavaDoc propertyName, String JavaDoc suffix) {
1271        String JavaDoc rawAliases[] = ( String JavaDoc[] ) subclassPropertyAliases.get( propertyName );
1272
1273        if ( rawAliases == null ) return null;
1274
1275        String JavaDoc result[] = new String JavaDoc[rawAliases.length];
1276        for ( int i = 0; i < rawAliases.length; i++ ) {
1277            result[i] = new Alias( suffix ).toUnquotedAliasString( rawAliases[i] );
1278        }
1279        return result;
1280    }
1281    
1282    public String JavaDoc[] getSubclassPropertyColumnNames(String JavaDoc propertyName) {
1283        //TODO: should we allow suffixes on these ?
1284
return ( String JavaDoc[] ) subclassPropertyColumnNames.get( propertyName );
1285    }
1286    
1287        
1288    
1289    //This is really ugly, but necessary:
1290
/**
1291     * Must be called by subclasses, at the end of their constructors
1292     */

1293    protected void initSubclassPropertyAliasesMap(PersistentClass model) throws MappingException {
1294
1295        // ALIASES
1296
internalInitSubclassPropertyAliasesMap( null, model.getSubclassPropertyClosureIterator() );
1297        
1298        // aliases for identifier ( alias.id )
1299
subclassPropertyAliases.put( ENTITY_ID, getIdentifierAliases() );
1300        subclassPropertyColumnNames.put( ENTITY_ID, getIdentifierColumnNames() );
1301        
1302        // aliases named identifier ( alias.idname )
1303
if ( hasIdentifierProperty() ) {
1304            subclassPropertyAliases.put( getIdentifierPropertyName(), getIdentifierAliases() );
1305            subclassPropertyColumnNames.put( getIdentifierPropertyName(), getIdentifierColumnNames() );
1306        }
1307
1308        // aliases for composite-id's
1309
if ( getIdentifierType().isComponentType() ) {
1310            // Fetch embedded identifiers propertynames from the "virtual" identifier component
1311
AbstractComponentType componentId = ( AbstractComponentType ) getIdentifierType();
1312            String JavaDoc[] idPropertyNames = componentId.getPropertyNames();
1313            String JavaDoc[] idAliases = getIdentifierAliases();
1314            String JavaDoc[] idColumnNames = getIdentifierColumnNames();
1315            
1316            for ( int i = 0; i < idPropertyNames.length; i++ ) {
1317                subclassPropertyAliases.put(
1318                        ENTITY_ID + "." + idPropertyNames[i],
1319                        new String JavaDoc[] { idAliases[i] }
1320                    );
1321                subclassPropertyColumnNames.put(
1322                        ENTITY_ID + "." + getIdentifierPropertyName() + "." + idPropertyNames[i],
1323                        new String JavaDoc[] { idColumnNames[i] }
1324                    );
1325                if (hasIdentifierProperty() && !ENTITY_ID.equals( getIdentifierPropertyName() ) ) {
1326                    subclassPropertyAliases.put(
1327                            getIdentifierPropertyName() + "." + idPropertyNames[i],
1328                            new String JavaDoc[] { idAliases[i] }
1329                        );
1330                    subclassPropertyColumnNames.put(
1331                            getIdentifierPropertyName() + "." + idPropertyNames[i],
1332                            new String JavaDoc[] { idColumnNames[i] }
1333                        );
1334                }
1335                else {
1336                    // embedded composite ids ( alias.idname1, alias.idname2 )
1337
subclassPropertyAliases.put( idPropertyNames[i], new String JavaDoc[] { idAliases[i] } );
1338                    subclassPropertyColumnNames.put( idPropertyNames[i], new String JavaDoc[] { idColumnNames[i] } );
1339                }
1340            }
1341        }
1342
1343        if ( entityMetamodel.isPolymorphic() ) {
1344            subclassPropertyAliases.put( ENTITY_CLASS,
1345                    new String JavaDoc[]{getDiscriminatorAlias()} );
1346            subclassPropertyColumnNames.put( ENTITY_CLASS,
1347                    new String JavaDoc[]{getDiscriminatorColumnName()} );
1348        }
1349
1350    }
1351
1352    private void internalInitSubclassPropertyAliasesMap(String JavaDoc path, Iterator JavaDoc propertyIterator) {
1353        while ( propertyIterator.hasNext() ) {
1354
1355            Property prop = ( Property ) propertyIterator.next();
1356            String JavaDoc propname = path == null ? prop.getName() : path + "." + prop.getName();
1357            if ( prop.isComposite() ) {
1358                Component component = ( Component ) prop.getValue();
1359                Iterator JavaDoc compProps = component.getPropertyIterator();
1360                internalInitSubclassPropertyAliasesMap( propname, compProps );
1361            }
1362            else {
1363                String JavaDoc[] aliases = new String JavaDoc[prop.getColumnSpan()];
1364                String JavaDoc[] cols = new String JavaDoc[prop.getColumnSpan()];
1365                Iterator JavaDoc colIter = prop.getColumnIterator();
1366                int l = 0;
1367                while ( colIter.hasNext() ) {
1368                    Selectable thing = ( Selectable ) colIter.next();
1369                    aliases[l] = thing.getAlias( getFactory().getDialect(), prop.getValue().getTable() );
1370                    cols[l] = thing.getText( getFactory().getDialect() ); // TODO: skip formulas?
1371
l++;
1372                }
1373
1374                subclassPropertyAliases.put( propname, aliases );
1375                subclassPropertyColumnNames.put( propname, cols );
1376            }
1377        }
1378
1379    }
1380
1381    public Object JavaDoc loadByUniqueKey(String JavaDoc propertyName, Object JavaDoc uniqueKey, SessionImplementor session)
1382            throws HibernateException {
1383        return getAppropriateUniqueKeyLoader( propertyName, session.getEnabledFilters() )
1384                .loadByUniqueKey( session, uniqueKey );
1385    }
1386
1387    private EntityLoader getAppropriateUniqueKeyLoader(String JavaDoc propertyName, Map JavaDoc enabledFilters) {
1388        
1389        final boolean useStaticLoader = ( enabledFilters == null || enabledFilters.isEmpty() )
1390                && propertyName.indexOf('.')<0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties
1391

1392        if ( useStaticLoader ) {
1393            return (EntityLoader) uniqueKeyLoaders.get( propertyName );
1394        }
1395        else {
1396            return createUniqueKeyLoader(
1397                    propertyMapping.toType(propertyName),
1398                    propertyMapping.toColumns(propertyName),
1399                    enabledFilters
1400                );
1401        }
1402    }
1403
1404    public int getPropertyIndex(String JavaDoc propertyName) {
1405        return entityMetamodel.getPropertyIndex(propertyName);
1406    }
1407
1408    protected void createUniqueKeyLoaders() throws MappingException {
1409        Type[] propertyTypes = getPropertyTypes();
1410        String JavaDoc[] propertyNames = getPropertyNames();
1411        for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
1412            if ( propertyUniqueness[i] ) {
1413                //don't need filters for the static loaders
1414
uniqueKeyLoaders.put(
1415                        propertyNames[i],
1416                        createUniqueKeyLoader(
1417                                propertyTypes[i],
1418                                getPropertyColumnNames( i ),
1419                                CollectionHelper.EMPTY_MAP
1420                            )
1421                    );
1422                //TODO: create uk loaders for component properties
1423
}
1424        }
1425    }
1426
1427    private EntityLoader createUniqueKeyLoader(Type uniqueKeyType, String JavaDoc[] columns, Map JavaDoc enabledFilters) {
1428        if ( uniqueKeyType.isEntityType() ) {
1429            String JavaDoc className = ( ( EntityType ) uniqueKeyType ).getAssociatedEntityName();
1430            uniqueKeyType = getFactory().getEntityPersister( className ).getIdentifierType();
1431        }
1432
1433        return new EntityLoader( this, columns, uniqueKeyType, 1, LockMode.NONE, getFactory(), enabledFilters );
1434    }
1435
1436    protected String JavaDoc getSQLWhereString(String JavaDoc alias) {
1437        return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias );
1438    }
1439
1440    protected boolean hasWhere() {
1441        return sqlWhereString != null;
1442    }
1443
1444    private void initOrdinaryPropertyPaths(Mapping mapping) throws MappingException {
1445        for ( int i = 0; i < getSubclassPropertyNameClosure().length; i++ ) {
1446            propertyMapping.initPropertyPaths( getSubclassPropertyNameClosure()[i],
1447                    getSubclassPropertyTypeClosure()[i],
1448                    getSubclassPropertyColumnNameClosure()[i],
1449                    getSubclassPropertyFormulaTemplateClosure()[i],
1450                    mapping );
1451        }
1452    }
1453
1454    private void initIdentifierPropertyPaths(Mapping mapping) throws MappingException {
1455        String JavaDoc idProp = getIdentifierPropertyName();
1456        if ( idProp != null ) {
1457            propertyMapping.initPropertyPaths( idProp, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
1458        }
1459        if ( entityMetamodel.getIdentifierProperty().isEmbedded() ) {
1460            propertyMapping.initPropertyPaths( null, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
1461        }
1462        propertyMapping.initPropertyPaths( ENTITY_ID, getIdentifierType(), getIdentifierColumnNames(), null, mapping );
1463    }
1464
1465    private void initDiscriminatorPropertyPath(Mapping mapping) throws MappingException {
1466        propertyMapping.initPropertyPaths( ENTITY_CLASS,
1467                getDiscriminatorType(),
1468                new String JavaDoc[]{getDiscriminatorColumnName()},
1469                new String JavaDoc[]{getDiscriminatorFormulaTemplate()},
1470                getFactory() );
1471    }
1472
1473    protected void initPropertyPaths(Mapping mapping) throws MappingException {
1474        initOrdinaryPropertyPaths(mapping);
1475        initOrdinaryPropertyPaths(mapping); //do two passes, for collection property-ref!
1476
initIdentifierPropertyPaths(mapping);
1477        if ( entityMetamodel.isPolymorphic() ) initDiscriminatorPropertyPath(mapping);
1478    }
1479
1480    protected UniqueEntityLoader createEntityLoader(LockMode lockMode, Map JavaDoc enabledFilters) throws MappingException {
1481        //TODO: disable batch loading if lockMode > READ?
1482
return BatchingEntityLoader.createBatchingEntityLoader( this, batchSize, lockMode, getFactory(), enabledFilters );
1483    }
1484
1485    protected UniqueEntityLoader createEntityLoader(LockMode lockMode) throws MappingException {
1486        return createEntityLoader( lockMode, CollectionHelper.EMPTY_MAP );
1487    }
1488
1489    protected boolean check(int rows, Serializable JavaDoc id, int tableNumber) throws HibernateException {
1490        if ( rows < 1 ) {
1491            if ( !isNullableTable( tableNumber ) ) {
1492                throw new StaleObjectStateException( getEntityName(), id );
1493            }
1494        }
1495        else if ( rows > 1 ) {
1496            throw new HibernateException(
1497                    "Duplicate identifier in table for: " +
1498                    MessageHelper.infoString( this, id, getFactory() )
1499            );
1500        }
1501        return rows > 0; //it could be zero if we have a "nullable" table
1502
}
1503
1504    protected String JavaDoc generateUpdateString(boolean[] includeProperty, int j, boolean useRowId) {
1505        return generateUpdateString( includeProperty, j, null, useRowId );
1506    }
1507
1508    /**
1509     * Generate the SQL that updates a row by id (and version)
1510     */

1511    protected String JavaDoc generateUpdateString(final boolean[] includeProperty,
1512                                          final int j,
1513                                          final Object JavaDoc[] oldFields,
1514                                          final boolean useRowId) {
1515
1516        Update update = new Update().setTableName( getTableName( j ) );
1517        
1518        // select the correct row by either pk or rowid
1519
if ( useRowId ) {
1520            update.setPrimaryKeyColumnNames( new String JavaDoc[]{rowIdName} ); //TODO: eventually, rowIdName[j]
1521
}
1522        else {
1523            update.setPrimaryKeyColumnNames( getKeyColumns( j ) );
1524        }
1525
1526        boolean hasColumns = false;
1527        for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
1528            if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
1529                // this is a property of the table, which we are updating
1530
update.addColumns( getPropertyColumnNames(i), propertyColumnUpdateable[i] );
1531                hasColumns = hasColumns || getPropertyColumnSpan( i ) > 0;
1532            }
1533        }
1534
1535        if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_VERSION ) {
1536            // this is the root (versioned) table, and we
1537
// are using version-based optimistic locking
1538
if ( includeProperty[ getVersionProperty() ] ) { //if we are not updating the version, also don't check it!
1539
update.setVersionColumnName( getVersionColumnName() );
1540                hasColumns = true;
1541            }
1542        }
1543        else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && oldFields != null ) {
1544            // we are using "all" or "dirty" property-based optimistic locking
1545

1546            boolean[] includeInWhere = entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_ALL ?
1547                    getPropertyUpdateability() : //optimistic-lock="all", include all updatable properties
1548
includeProperty; //optimistic-lock="dirty", include all properties we are updating this time
1549

1550            for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
1551                boolean[] versionability = getPropertyVersionability();
1552                Type[] types = getPropertyTypes();
1553                boolean include = includeInWhere[i] &&
1554                        isPropertyOfTable( i, j ) &&
1555                        versionability[i];
1556                if ( include ) {
1557                    // this property belongs to the table, and it is not specifically
1558
// excluded from optimistic locking by optimistic-lock="false"
1559
String JavaDoc[] propertyColumnNames = getPropertyColumnNames( i );
1560                    boolean[] propertyNullness = types[i].toColumnNullness( oldFields[i], getFactory() );
1561                    for ( int k=0; k<propertyNullness.length; k++ ) {
1562                        if ( propertyNullness[k] ) {
1563                            update.addWhereColumn( propertyColumnNames[k] );
1564                        }
1565                        else {
1566                            update.addWhereColumn( propertyColumnNames[k], " is null" );
1567                        }
1568                    }
1569                }
1570            }
1571
1572        }
1573
1574        if ( getFactory().getSettings().isCommentsEnabled() ) {
1575            update.setComment( "update " + getEntityName() );
1576        }
1577
1578        return hasColumns ? update.toStatementString() : null;
1579    }
1580
1581    protected String JavaDoc generateInsertString(boolean[] includeProperty, int j) {
1582        return generateInsertString( false, includeProperty, j );
1583    }
1584
1585    protected String JavaDoc generateInsertString(boolean identityInsert, boolean[] includeProperty) {
1586        return generateInsertString( identityInsert, includeProperty, 0 );
1587    }
1588
1589    /**
1590     * Generate the SQL that inserts a row
1591     */

1592    protected String JavaDoc generateInsertString(boolean identityInsert, boolean[] includeProperty, int j) {
1593
1594        Insert insert = new Insert( getFactory().getDialect() )
1595                .setTableName( getTableName( j ) );
1596        
1597        // add normal properties
1598
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
1599            if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
1600                // this property belongs on the table and is to be inserted
1601
insert.addColumns( getPropertyColumnNames(i), propertyColumnInsertable[i] );
1602            }
1603        }
1604        
1605        // add the discriminator
1606
if ( j == 0 ) addDiscriminatorToInsert( insert );
1607        
1608        // add the primary key
1609
if ( j == 0 && identityInsert ) {
1610            insert.addIdentityColumn( getKeyColumns( 0 )[0] );
1611        }
1612        else {
1613            insert.addColumns( getKeyColumns( j ) );
1614        }
1615
1616        if ( getFactory().getSettings().isCommentsEnabled() ) {
1617            insert.setComment( "insert " + getEntityName() );
1618        }
1619
1620        String JavaDoc result = insert.toStatementString();
1621        
1622        // append the SQL to return the generated identifier
1623
if ( j == 0 && identityInsert && useInsertSelectIdentity() ) { //TODO: suck into Insert
1624
result = getFactory().getDialect().appendIdentitySelectToInsert( result );
1625        }
1626
1627        return result;
1628    }
1629
1630    /**
1631     * Generate the SQL that deletes a row by id (and version)
1632     */

1633    protected String JavaDoc generateDeleteString(int j) {
1634        Delete delete = new Delete()
1635                .setTableName( getTableName( j ) )
1636                .setPrimaryKeyColumnNames( getKeyColumns( j ) );
1637        if ( j == 0 ) delete.setVersionColumnName( getVersionColumnName() );
1638        if ( getFactory().getSettings().isCommentsEnabled() ) {
1639            delete.setComment( "delete " + getEntityName() );
1640        }
1641        return delete.toStatementString();
1642    }
1643
1644    protected int dehydrate(
1645            Serializable JavaDoc id,
1646            Object JavaDoc[] fields,
1647            boolean[] includeProperty,
1648            boolean[][] includeColumns,
1649            int j,
1650            PreparedStatement JavaDoc st,
1651            SessionImplementor session)
1652    throws HibernateException, SQLException JavaDoc {
1653        return dehydrate( id, fields, null, includeProperty, includeColumns, j, st, session, 1 );
1654    }
1655
1656    /**
1657     * Marshall the fields of a persistent instance to a prepared statement
1658     */

1659    protected int dehydrate(final Serializable JavaDoc id,
1660                            final Object JavaDoc[] fields,
1661                            final Object JavaDoc rowId,
1662                            final boolean[] includeProperty,
1663                            final boolean[][] includeColumns,
1664                            final int j,
1665                            final PreparedStatement JavaDoc ps,
1666                            final SessionImplementor session,
1667                            int index)
1668            throws SQLException JavaDoc, HibernateException {
1669
1670        if ( log.isTraceEnabled() ) {
1671            log.trace( "Dehydrating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
1672        }
1673
1674        for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
1675            if ( includeProperty[i] && isPropertyOfTable( i, j ) ) {
1676                getPropertyTypes()[i].nullSafeSet( ps, fields[i], index, includeColumns[i], session );
1677                //index += getPropertyColumnSpan( i );
1678
index += ArrayHelper.countTrue( includeColumns[i] ); //TODO: this is kinda slow...
1679
}
1680        }
1681
1682        if ( rowId != null ) {
1683            ps.setObject( index, rowId );
1684            index += 1;
1685        }
1686        else if ( id != null ) {
1687            getIdentifierType().nullSafeSet( ps, id, index, session );
1688            index += getIdentifierColumnSpan();
1689        }
1690
1691        return index;
1692
1693    }
1694
1695    /**
1696     * Unmarshall the fields of a persistent instance from a result set,
1697     * without resolving associations or collections. Question: should
1698     * this really be here, or should it be sent back to Loader?
1699     */

1700    public Object JavaDoc[] hydrate(final ResultSet JavaDoc rs,
1701                            final Serializable JavaDoc id,
1702                            final Object JavaDoc object,
1703                            final Loadable rootLoadable,
1704                            final String JavaDoc[][] suffixedPropertyColumns,
1705                            final boolean allProperties,
1706                            final SessionImplementor session)
1707            throws SQLException JavaDoc, HibernateException {
1708
1709        if ( log.isTraceEnabled() ) {
1710            log.trace( "Hydrating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
1711        }
1712
1713        final BasicEntityPersister rootPersister = (BasicEntityPersister) rootLoadable;
1714
1715        final boolean hasDeferred = rootPersister.hasSequentialSelect();
1716        PreparedStatement JavaDoc sequentialSelect = null;
1717        ResultSet JavaDoc sequentialResultSet = null;
1718        try {
1719
1720            if ( hasDeferred ) {
1721                final String JavaDoc sql = rootPersister.getSequentialSelect( getEntityName() );
1722                if ( sql != null ) {
1723                    //TODO: I am not so sure about the exception handling in this bit!
1724
sequentialSelect = session.getBatcher().prepareSelectStatement( sql );
1725                    rootPersister.getIdentifierType().nullSafeSet( sequentialSelect, id, 1, session );
1726                    sequentialResultSet = sequentialSelect.executeQuery();
1727                    sequentialResultSet.next();
1728                }
1729            }
1730
1731            final String JavaDoc[] propNames = getPropertyNames();
1732            final Type[] types = getPropertyTypes();
1733            final Object JavaDoc[] values = new Object JavaDoc[types.length];
1734            final boolean[] laziness = getPropertyLaziness();
1735            final String JavaDoc[] propSubclassNames = getSubclassPropertySubclassNameClosure();
1736
1737            for ( int i = 0; i < types.length; i++ ) {
1738                if ( !propertySelectable[i] ) {
1739                    values[i] = BackrefPropertyAccessor.UNKNOWN;
1740                }
1741                else if ( allProperties || !laziness[i] ) {
1742                    //decide which ResultSet to get the property value from:
1743
final boolean propertyIsDeferred = hasDeferred &&
1744                            rootPersister.isSubclassPropertyDeferred( propNames[i], propSubclassNames[i] );
1745                    final ResultSet JavaDoc propertyResultSet = propertyIsDeferred ? sequentialResultSet : rs;
1746                    final String JavaDoc[] cols = propertyIsDeferred ?
1747                            propertyColumnAliases[i] : suffixedPropertyColumns[i];
1748
1749                    values[i] = types[i].hydrate( propertyResultSet, cols, session, object );
1750                }
1751                else {
1752                    values[i] = LazyPropertyInitializer.UNFETCHED_PROPERTY;
1753                }
1754            }
1755
1756            if ( sequentialResultSet != null ) sequentialResultSet.close();
1757
1758            return values;
1759
1760        }
1761        finally {
1762            if ( sequentialSelect != null ) {
1763                session.getBatcher().closeStatement( sequentialSelect );
1764            }
1765        }
1766    }
1767
1768    protected boolean useInsertSelectIdentity() {
1769        return !useGetGeneratedKeys() && getFactory().getDialect().supportsInsertSelectIdentity();
1770    }
1771
1772    protected boolean useGetGeneratedKeys() {
1773        return getFactory().getSettings().isGetGeneratedKeysEnabled();
1774    }
1775    
1776    protected String JavaDoc getSequentialSelect(String JavaDoc entityName) {
1777        throw new UnsupportedOperationException JavaDoc("no sequential selects");
1778    }
1779
1780    /**
1781     * Perform an SQL INSERT, and then retrieve a generated identifier
1782     */

1783    protected Serializable JavaDoc insert(final Object JavaDoc[] fields,
1784                                  final boolean[] notNull,
1785                                  String JavaDoc sql,
1786                                  final Object JavaDoc object,
1787                                  final SessionImplementor session)
1788            throws HibernateException {
1789
1790        if ( log.isTraceEnabled() ) {
1791            log.trace( "Inserting entity: " + getEntityName() + " (native id)" );
1792            if ( isVersioned() ) log.trace( "Version: " + Versioning.getVersion( fields, this ) );
1793        }
1794
1795        try {
1796
1797            //do the insert
1798
PreparedStatement JavaDoc insert = session.getBatcher().prepareStatement( sql, useGetGeneratedKeys() );
1799            try {
1800                dehydrate( null, fields, notNull, propertyColumnInsertable, 0, insert, session );
1801
1802                if ( useInsertSelectIdentity() ) {
1803                    if ( !insert.execute() ) {
1804                        while ( !insert.getMoreResults() && insert.getUpdateCount() != -1 ) {
1805                            continue; // Do nothing (but stop checkstyle from complaining).
1806
}
1807                    }
1808                    //note early exit!
1809
ResultSet JavaDoc rs = insert.getResultSet();
1810                    try {
1811                        return IdentifierGeneratorFactory.getGeneratedIdentity( rs, getIdentifierType() );
1812                    }
1813                    finally {
1814                        rs.close();
1815                    }
1816                }
1817                else if ( useGetGeneratedKeys() ) {
1818                    insert.executeUpdate();
1819                    //note early exit!
1820
return IdentifierGeneratorFactory.getGeneratedIdentity(
1821                            GetGeneratedKeysHelper.getGeneratedKey(insert),
1822                            getIdentifierType()
1823                    );
1824                }
1825                else {
1826                    insert.executeUpdate();
1827                }
1828
1829            }
1830            finally {
1831                session.getBatcher().closeStatement( insert );
1832            }
1833
1834        }
1835        catch ( SQLException JavaDoc sqle ) {
1836            throw JDBCExceptionHelper.convert(
1837                    getFactory().getSQLExceptionConverter(),
1838                    sqle,
1839                    "could not insert: " + MessageHelper.infoString(this),
1840                    sql
1841                );
1842        }
1843        
1844        return ( (PostInsertIdentifierGenerator) getIdentifierGenerator() ).getGenerated(session, object, this);
1845
1846    }
1847    
1848    public String JavaDoc getIdentitySelectString() {
1849        //TODO: cache this in an instvar
1850
return getFactory().getDialect().getIdentitySelectString(
1851                getTableName(0),
1852                getKeyColumns(0)[0],
1853                getIdentifierType().sqlTypes( getFactory() )[0]
1854        );
1855    }
1856    
1857    public String JavaDoc getSelectByUniqueKeyString(String JavaDoc propertyName) {
1858        return new SimpleSelect( getFactory().getDialect() )
1859            .setTableName( getTableName(0) )
1860            .addColumns( getKeyColumns(0) )
1861            .addCondition( getPropertyColumnNames(propertyName), "=?" )
1862            .toStatementString();
1863    }
1864
1865    /**
1866     * Perform an SQL INSERT
1867     */

1868    protected void insert(final Serializable JavaDoc id,
1869                          final Object JavaDoc[] fields,
1870                          final boolean[] notNull,
1871                          final int j,
1872                          final String JavaDoc sql,
1873                          final Object JavaDoc object,
1874                          final SessionImplementor session)
1875            throws HibernateException {
1876
1877        if ( isInverseTable( j ) ) return;
1878        
1879        //note: it is conceptually possible that a UserType could map null to
1880
// a non-null value, so the following is arguable:
1881
if ( isNullableTable( j ) && isAllNull( fields, j ) ) return;
1882
1883        if ( log.isTraceEnabled() ) {
1884            log.trace( "Inserting entity: " + MessageHelper.infoString( this, id, getFactory() ) );
1885            if ( j == 0 && isVersioned() ) log.trace( "Version: " + Versioning.getVersion( fields, this ) );
1886        }
1887
1888        boolean callable = isInsertCallable( j );
1889        final boolean useBatch = j == 0 && !callable; //we can't batch joined inserts, *especially* not if it is an identity insert
1890
try {
1891
1892            // Render the SQL query
1893
final PreparedStatement JavaDoc insert;
1894            if ( callable ) {
1895                insert = session.getBatcher().prepareCallableStatement( sql );
1896            }
1897            else if ( useBatch ) {
1898                insert = session.getBatcher().prepareBatchStatement( sql );
1899            }
1900            else {
1901                insert = session.getBatcher().prepareStatement( sql );
1902            }
1903
1904            try {
1905
1906                // Write the values of fields onto the prepared statement - we MUST use the state at the time the
1907
// insert was issued (cos of foreign key constraints). Not necessarily the object's current state
1908

1909                dehydrate( id, fields, notNull, propertyColumnInsertable, j, insert, session );
1910
1911                if ( useBatch ) {
1912                    session.getBatcher().addToBatch( 1 );
1913                }
1914                else {
1915                    insert.executeUpdate();
1916                }
1917
1918            }
1919            catch ( SQLException JavaDoc sqle ) {
1920                if ( useBatch ) session.getBatcher().abortBatch( sqle );
1921                throw sqle;
1922            }
1923            finally {
1924                if ( !useBatch ) session.getBatcher().closeStatement( insert );
1925            }
1926        }
1927        catch ( SQLException JavaDoc sqle ) {
1928            throw JDBCExceptionHelper.convert(
1929                    getFactory().getSQLExceptionConverter(),
1930                    sqle,
1931                    "could not insert: " + MessageHelper.infoString( this ),
1932                    sql
1933                );
1934        }
1935
1936    }
1937
1938    /**
1939     * Perform an SQL UPDATE or SQL INSERT
1940     */

1941    protected void updateOrInsert(final Serializable JavaDoc id,
1942                                  final Object JavaDoc[] fields,
1943                                  final Object JavaDoc[] oldFields,
1944                                  final Object JavaDoc rowId,
1945                                  final boolean[] includeProperty,
1946                                  final int j,
1947                                  final Object JavaDoc oldVersion,
1948                                  final Object JavaDoc object,
1949                                  final String JavaDoc sql,
1950                                  final SessionImplementor session)
1951            throws HibernateException {
1952
1953        if ( !isInverseTable( j ) ) {
1954
1955            final boolean isRowToUpdate;
1956            if ( isNullableTable( j ) && oldFields != null && isAllNull( oldFields, j ) ) {
1957                //don't bother trying to update, we know there is no row there yet
1958
isRowToUpdate = false;
1959            }
1960            else if ( isNullableTable( j ) && isAllNull( fields, j ) ) {
1961                //if all fields are null, we might need to delete existing row
1962
isRowToUpdate = true;
1963                delete( id, oldVersion, j, object, getSQLDeleteStrings()[j], session );
1964            }
1965            else {
1966                //there is probably a row there, so try to update
1967
//if no rows were updated, we will find out
1968
isRowToUpdate = update( id, fields, oldFields, rowId, includeProperty, j, oldVersion, object, sql, session );
1969            }
1970    
1971            if ( !isRowToUpdate && !isAllNull( fields, j ) ) {
1972                // assume that the row was not there since it previously had only null
1973
// values, so do an INSERT instead
1974
//TODO: does not respect dynamic-insert
1975
insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
1976            }
1977
1978        }
1979        
1980    }
1981
1982    protected boolean update(final Serializable JavaDoc id,
1983                             final Object JavaDoc[] fields,
1984                             final Object JavaDoc[] oldFields,
1985                             final Object JavaDoc rowId,
1986                             final boolean[] includeProperty,
1987                             final int j,
1988                             final Object JavaDoc oldVersion,
1989                             final Object JavaDoc object,
1990                             final String JavaDoc sql,
1991                             final SessionImplementor session)
1992            throws HibernateException {
1993
1994        final boolean useVersion = j == 0 && isVersioned();
1995        final boolean callable = isUpdateCallable( j );
1996        final boolean useBatch = j == 0 && !callable && isBatchable(); //note: updates to joined tables can't be batched...
1997

1998        if ( log.isTraceEnabled() ) {
1999            log.trace( "Updating entity: " + MessageHelper.infoString( this, id, getFactory() ) );
2000            if ( useVersion ) log.trace( "Existing version: " + oldVersion + " -> New version: " + fields[getVersionProperty()] );
2001        }
2002
2003        try {
2004
2005            int index = 1; // starting index
2006
final PreparedStatement JavaDoc update;
2007            if ( callable ) {
2008                CallableStatement JavaDoc callstatement = session.getBatcher().prepareCallableStatement( sql );
2009                callstatement.registerOutParameter( index++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ?
2010
update = callstatement;
2011            }
2012            else if ( useBatch ) {
2013                update = session.getBatcher().prepareBatchStatement( sql );
2014            }
2015            else {
2016                update = session.getBatcher().prepareStatement( sql );
2017            }
2018
2019            try {
2020
2021                //Now write the values of fields onto the prepared statement
2022
index = dehydrate( id, fields, rowId, includeProperty, propertyColumnUpdateable, j, update, session, index );
2023    
2024                // Write any appropriate versioning conditional parameters
2025
if ( useVersion && Versioning.OPTIMISTIC_LOCK_VERSION == entityMetamodel.getOptimisticLockMode() ) {
2026                    getVersionType().nullSafeSet( update, oldVersion, index, session );
2027                }
2028                else if ( entityMetamodel.getOptimisticLockMode() > Versioning.OPTIMISTIC_LOCK_VERSION && oldFields != null ) {
2029                    boolean[] versionability = getPropertyVersionability(); //TODO: is this really necessary????
2030
boolean[] includeOldField = entityMetamodel.getOptimisticLockMode() == Versioning.OPTIMISTIC_LOCK_ALL ?
2031                            getPropertyUpdateability() : includeProperty;
2032                    Type[] types = getPropertyTypes();
2033                    for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {
2034                        boolean include = includeOldField[i] &&
2035                                isPropertyOfTable( i, j ) &&
2036                                versionability[i]; //TODO: is this really necessary????
2037
if ( include ) {
2038                            boolean[] settable = types[i].toColumnNullness( oldFields[i], getFactory() );
2039                            types[i].nullSafeSet(
2040                                    update,
2041                                    oldFields[i],
2042                                    index,
2043                                    settable,
2044                                    session
2045                                );
2046                            index += ArrayHelper.countTrue(settable);
2047                        }
2048                    }
2049                }
2050
2051                if ( useBatch ) {
2052                    session.getBatcher().addToBatch( 1 );
2053                    return true;
2054                }
2055                else {
2056                    return check( update.executeUpdate(), id, j );
2057                }
2058
2059            }
2060            catch ( SQLException JavaDoc sqle ) {
2061                if ( useBatch ) session.getBatcher().abortBatch( sqle );
2062                throw sqle;
2063            }
2064            finally {
2065                if ( !useBatch ) session.getBatcher().closeStatement( update );
2066            }
2067
2068        }
2069        catch ( SQLException JavaDoc sqle ) {
2070            throw JDBCExceptionHelper.convert(
2071                    getFactory().getSQLExceptionConverter(),
2072                    sqle,
2073                    "could not update: " + MessageHelper.infoString( this, id, getFactory() ),
2074                    sql
2075                );
2076        }
2077    }
2078
2079    /**
2080     * Perform an SQL DELETE
2081     */

2082    protected void delete(final Serializable JavaDoc id,
2083                          final Object JavaDoc version,
2084                          final int j,
2085                          final Object JavaDoc object,
2086                          final String JavaDoc sql,
2087                          final SessionImplementor session)
2088            throws HibernateException {
2089        
2090        if ( isInverseTable( j ) ) return;
2091
2092        final boolean useVersion = j == 0 && isVersioned();
2093        final boolean callable = isDeleteCallable( j );
2094        final boolean useBatch = j == 0 && isBatchable() && !callable;
2095
2096        if ( log.isTraceEnabled() ) {
2097            log.trace( "Deleting entity: " + MessageHelper.infoString( this, id, getFactory() ) );
2098            if ( useVersion ) log.trace( "Version: " + version );
2099        }
2100
2101        if ( isTableCascadeDeleteEnabled( j ) ) {
2102            if ( log.isTraceEnabled() ) {
2103                log.trace( "delete handled by foreign key constraint: " + getTableName( j ) );
2104            }
2105            return; //EARLY EXIT!
2106
}
2107
2108        try {
2109
2110            //Render the SQL query
2111
PreparedStatement JavaDoc delete;
2112            int index = 1;
2113            if ( callable ) {
2114                CallableStatement JavaDoc callstatement = session.getBatcher().prepareCallableStatement( sql );
2115                callstatement.registerOutParameter( index++, Types.NUMERIC ); // TODO: should we require users to return number of deleted rows ?
2116
delete = callstatement;
2117            }
2118            else if ( useBatch ) {
2119                delete = session.getBatcher().prepareBatchStatement( sql );
2120            }
2121            else {
2122                delete = session.getBatcher().prepareStatement( sql );
2123            }
2124
2125            try {
2126
2127                // Do the key. The key is immutable so we can use the _current_ object state - not necessarily
2128
// the state at the time the delete was issued
2129

2130                getIdentifierType().nullSafeSet( delete, id, index, session );
2131
2132                // We should use the _current_ object state (ie. after any updates that occurred during flush)
2133

2134                if ( useVersion ) {
2135                    getVersionType().nullSafeSet( delete, version, getIdentifierColumnSpan() + index, session );
2136                }
2137
2138                if ( useBatch ) {
2139                    session.getBatcher().addToBatch( 1 );
2140                }
2141                else {
2142                    check( delete.executeUpdate(), id, j );
2143                }
2144
2145            }
2146            catch ( SQLException JavaDoc sqle ) {
2147                if ( useBatch ) session.getBatcher().abortBatch( sqle );
2148                throw sqle;
2149            }
2150            finally {
2151                if ( !useBatch ) session.getBatcher().closeStatement( delete );
2152            }
2153
2154        }
2155        catch ( SQLException JavaDoc sqle ) {
2156            throw JDBCExceptionHelper.convert(
2157                    getFactory().getSQLExceptionConverter(),
2158                    sqle,
2159                    "could not delete: " +
2160                    MessageHelper.infoString( this, id, getFactory() ),
2161                    sql
2162                );
2163
2164        }
2165
2166    }
2167
2168    private String JavaDoc[] getUpdateStrings(boolean byRowId, boolean lazy) {
2169        if ( byRowId ) {
2170            return lazy ? getSQLLazyUpdateByRowIdStrings() : getSQLUpdateByRowIdStrings();
2171        }
2172        else {
2173            return lazy ? getSQLLazyUpdateStrings() : getSQLUpdateStrings();
2174        }
2175    }
2176
2177    /**
2178     * Update an object
2179     */

2180    public void update(final Serializable JavaDoc id,
2181                       final Object JavaDoc[] fields,
2182                       final int[] dirtyFields,
2183                       final boolean hasDirtyCollection,
2184                       final Object JavaDoc[] oldFields,
2185                       final Object JavaDoc oldVersion,
2186                       final Object JavaDoc object,
2187                       final Object JavaDoc rowId,
2188                       final SessionImplementor session)
2189            throws HibernateException {
2190
2191        //note: dirtyFields==null means we had no snapshot, and we couldn't get one using select-before-update
2192
// oldFields==null just means we had no snapshot to begin with (we might have used select-before-update to get the dirtyFields)
2193

2194        final boolean[] tableUpdateNeeded = getTableUpdateNeeded( dirtyFields, hasDirtyCollection );
2195        final int span = getTableSpan();
2196
2197        final boolean[] propsToUpdate;
2198        final String JavaDoc[] updateStrings;
2199        if ( entityMetamodel.isDynamicUpdate() && dirtyFields != null ) {
2200            // For the case of dynamic-update="true", we need to generate the UPDATE SQL
2201
propsToUpdate = getPropertiesToUpdate( dirtyFields, hasDirtyCollection );
2202            // don't need to check laziness (dirty checking algorithm handles that)
2203
updateStrings = new String JavaDoc[span];
2204            for ( int j = 0; j < span; j++ ) {
2205                updateStrings[j] = tableUpdateNeeded[j] ?
2206                        generateUpdateString( propsToUpdate, j, oldFields, j == 0 && rowId != null ) :
2207                        null;
2208            }
2209        }
2210        else {
2211            // For the case of dynamic-update="false", or no snapshot, we use the static SQL
2212
updateStrings = getUpdateStrings(
2213                    rowId != null,
2214                    hasUninitializedLazyProperties( object, session.getEntityMode() )
2215                );
2216            propsToUpdate = getPropertyUpdateability( object, session.getEntityMode() );
2217        }
2218
2219        for ( int j = 0; j < span; j++ ) {
2220            // Now update only the tables with dirty properties (and the table with the version number)
2221
if ( tableUpdateNeeded[j] ) {
2222                updateOrInsert(
2223                        id,
2224                        fields,
2225                        oldFields,
2226                        j == 0 ? rowId : null,
2227                        propsToUpdate,
2228                        j,
2229                        oldVersion,
2230                        object,
2231                        updateStrings[j],
2232                        session
2233                    );
2234            }
2235        }
2236    }
2237
2238    public Serializable JavaDoc insert(Object JavaDoc[] fields, Object JavaDoc object, SessionImplementor session)
2239            throws HibernateException {
2240
2241        final int span = getTableSpan();
2242        final Serializable JavaDoc id;
2243        if ( entityMetamodel.isDynamicInsert() ) {
2244            // For the case of dynamic-insert="true", we need to generate the INSERT SQL
2245
boolean[] notNull = getPropertiesToInsert( fields );
2246            id = insert( fields, notNull, generateInsertString( true, notNull ), object, session );
2247            for ( int j = 1; j < span; j++ ) {
2248                insert( id, fields, notNull, j, generateInsertString( notNull, j ), object, session );
2249            }
2250        }
2251        else {
2252            // For the case of dynamic-insert="false", use the static SQL
2253
id = insert( fields, getPropertyInsertability(), getSQLIdentityInsertString(), object, session );
2254            for ( int j = 1; j < span; j++ ) {
2255                insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
2256            }
2257        }
2258        return id;
2259    }
2260
2261    public void insert(Serializable JavaDoc id, Object JavaDoc[] fields, Object JavaDoc object, SessionImplementor session)
2262            throws HibernateException {
2263
2264        final int span = getTableSpan();
2265        if ( entityMetamodel.isDynamicInsert() ) {
2266            // For the case of dynamic-insert="true", we need to generate the INSERT SQL
2267
boolean[] notNull = getPropertiesToInsert( fields );
2268            for ( int j = 0; j < span; j++ ) {
2269                insert( id, fields, notNull, j, generateInsertString( notNull, j ), object, session );
2270            }
2271        }
2272        else {
2273            // For the case of dynamic-insert="false", use the static SQL
2274
for ( int j = 0; j < span; j++ ) {
2275                insert( id, fields, getPropertyInsertability(), j, getSQLInsertStrings()[j], object, session );
2276            }
2277        }
2278    }
2279
2280    /**
2281     * Delete an object
2282     */

2283    public void delete(Serializable JavaDoc id, Object JavaDoc version, Object JavaDoc object, SessionImplementor session)
2284            throws HibernateException {
2285
2286        final int span = getTableSpan();
2287        for ( int j = span - 1; j >= 0; j-- ) {
2288            delete( id, version, j, object, getSQLDeleteStrings()[j], session );
2289        }
2290
2291    }
2292
2293    protected void logStaticSQL() {
2294        if ( log.isDebugEnabled() ) {
2295            log.debug( "Static SQL for entity: " + getEntityName() );
2296            if ( sqlLazySelectString != null ) log.debug( " Lazy select: " + sqlLazySelectString );
2297            if ( sqlVersionSelectString != null ) log.debug( " Version select: " + sqlVersionSelectString );
2298            if ( sqlSnapshotSelectString != null ) log.debug( " Snapshot select: " + sqlSnapshotSelectString );
2299            for ( int j = 0; j < getTableSpan(); j++ ) {
2300                log.debug( " Insert " + j + ": " + getSQLInsertStrings()[j] );
2301                log.debug( " Update " + j + ": " + getSQLUpdateStrings()[j] );
2302                log.debug( " Delete " + j + ": " + getSQLDeleteStrings()[j] );
2303
2304            }
2305            if ( sqlIdentityInsertString != null ) log.debug( " Identity insert: " + sqlIdentityInsertString );
2306            if ( sqlUpdateByRowIdString != null ) log.debug( " Update by row id (all fields): " + sqlUpdateByRowIdString );
2307            if ( sqlLazyUpdateByRowIdString != null ) log.debug( " Update by row id (non-lazy fields): " + sqlLazyUpdateByRowIdString );
2308        }
2309    }
2310
2311    public String JavaDoc filterFragment(String JavaDoc alias, Map JavaDoc enabledFilters) throws MappingException {
2312        final StringBuffer JavaDoc sessionFilterFragment = new StringBuffer JavaDoc();
2313        filterHelper.render( sessionFilterFragment, generateFilterConditionAlias( alias ), enabledFilters );
2314
2315        return sessionFilterFragment.append( filterFragment( alias ) ).toString();
2316    }
2317
2318    protected String JavaDoc generateFilterConditionAlias(String JavaDoc rootAlias) {
2319        return rootAlias;
2320    }
2321
2322    public String JavaDoc oneToManyFilterFragment(String JavaDoc alias) throws MappingException {
2323        return "";
2324    }
2325
2326    public String JavaDoc fromJoinFragment(String JavaDoc alias, boolean innerJoin, boolean includeSubclasses) {
2327        return getSubclassTableSpan() == 1 ?
2328                "" : //just a performance opt!
2329
createJoin( alias, innerJoin, includeSubclasses ).toFromFragmentString();
2330    }
2331
2332    public String JavaDoc whereJoinFragment(String JavaDoc alias, boolean innerJoin, boolean includeSubclasses) {
2333        return getSubclassTableSpan() == 1 ?
2334                "" : //just a performance opt!
2335
createJoin( alias, innerJoin, includeSubclasses ).toWhereFragmentString();
2336    }
2337
2338    protected boolean isSubclassTableLazy(int j) {
2339        return false;
2340    }
2341
2342    protected JoinFragment createJoin(String JavaDoc name, boolean innerJoin, boolean includeSubclasses) {
2343        final String JavaDoc[] idCols = StringHelper.qualify( name, getIdentifierColumnNames() ); //all joins join to the pk of the driving table
2344
final JoinFragment join = getFactory().getDialect().createOuterJoinFragment();
2345        final int tableSpan = getSubclassTableSpan();
2346        for ( int j = 1; j < tableSpan; j++ ) { //notice that we skip the first table; it is the driving table!
2347
final boolean joinIsIncluded = isClassOrSuperclassTable( j ) ||
2348                    ( includeSubclasses && !isSubclassTableSequentialSelect( j ) && !isSubclassTableLazy( j ) );
2349            if ( joinIsIncluded ) {
2350                join.addJoin( getSubclassTableName( j ),
2351                        generateTableAlias( name, j ),
2352                        idCols,
2353                        getSubclassTableKeyColumns( j ),
2354                        innerJoin && isClassOrSuperclassTable( j ) && !isInverseTable( j ) && !isNullableTable( j ) ?
2355                        JoinFragment.INNER_JOIN : //we can inner join to superclass tables (the row MUST be there)
2356
JoinFragment.LEFT_OUTER_JOIN //we can never inner join to subclass tables
2357
);
2358            }
2359        }
2360        return join;
2361    }
2362
2363    protected JoinFragment createJoin(int[] tableNumbers, String JavaDoc drivingAlias) {
2364        final String JavaDoc[] keyCols = StringHelper.qualify( drivingAlias, getSubclassTableKeyColumns( tableNumbers[0] ) );
2365        final JoinFragment jf = getFactory().getDialect().createOuterJoinFragment();
2366        for ( int i = 1; i < tableNumbers.length; i++ ) { //skip the driving table
2367
final int j = tableNumbers[i];
2368            jf.addJoin( getSubclassTableName( j ),
2369                    generateTableAlias( getRootAlias(), j ),
2370                    keyCols,
2371                    getSubclassTableKeyColumns( j ),
2372                    isInverseSubclassTable( j ) || isNullableSubclassTable( j ) ?
2373                    JoinFragment.LEFT_OUTER_JOIN :
2374                    JoinFragment.INNER_JOIN );
2375        }
2376        return jf;
2377    }
2378
2379    protected SelectFragment createSelect(final int[] subclassColumnNumbers,
2380                                          final int[] subclassFormulaNumbers) {
2381
2382        SelectFragment selectFragment = new SelectFragment();
2383
2384        int[] columnTableNumbers = getSubclassColumnTableNumberClosure();
2385        String JavaDoc[] columnAliases = getSubclassColumnAliasClosure();
2386        String JavaDoc[] columns = getSubclassColumnClosure();
2387        for ( int i = 0; i < subclassColumnNumbers.length; i++ ) {
2388            if ( subclassColumnSelectableClosure[i] ) {
2389                int columnNumber = subclassColumnNumbers[i];
2390                final String JavaDoc subalias = generateTableAlias( getRootAlias(), columnTableNumbers[columnNumber] );
2391                selectFragment.addColumn( subalias, columns[columnNumber], columnAliases[columnNumber] );
2392            }
2393        }
2394
2395        int[] formulaTableNumbers = getSubclassFormulaTableNumberClosure();
2396        String JavaDoc[] formulaTemplates = getSubclassFormulaTemplateClosure();
2397        String JavaDoc[] formulaAliases = getSubclassFormulaAliasClosure();
2398        for ( int i = 0; i < subclassFormulaNumbers.length; i++ ) {
2399            int formulaNumber = subclassFormulaNumbers[i];
2400            final String JavaDoc subalias = generateTableAlias( getRootAlias(), formulaTableNumbers[formulaNumber] );
2401            selectFragment.addFormula( subalias, formulaTemplates[formulaNumber], formulaAliases[formulaNumber] );
2402        }
2403
2404        return selectFragment;
2405    }
2406
2407    protected String JavaDoc createFrom(int tableNumber, String JavaDoc alias) {
2408        return getSubclassTableName( tableNumber ) + ' ' + alias;
2409    }
2410
2411    protected String JavaDoc createWhereByKey(int tableNumber, String JavaDoc alias) {
2412        //TODO: move to .sql package, and refactor with similar things!
2413
return StringHelper.join( "=? and ",
2414                StringHelper.qualify( alias, getSubclassTableKeyColumns( tableNumber ) ) ) + "=?";
2415    }
2416
2417    protected String JavaDoc renderSelect(final int[] tableNumbers,
2418                                  final int[] columnNumbers,
2419                                  final int[] formulaNumbers) {
2420
2421        Arrays.sort( tableNumbers ); //get 'em in the right order (not that it really matters)
2422

2423        //render the where and from parts
2424
int drivingTable = tableNumbers[0];
2425        final String JavaDoc drivingAlias = generateTableAlias( getRootAlias(), drivingTable ); //we *could* regerate this inside each called method!
2426
final String JavaDoc where = createWhereByKey( drivingTable, drivingAlias );
2427        final String JavaDoc from = createFrom( drivingTable, drivingAlias );
2428    
2429        //now render the joins
2430
JoinFragment jf = createJoin( tableNumbers, drivingAlias );
2431        
2432        //now render the select clause
2433
SelectFragment selectFragment = createSelect( columnNumbers, formulaNumbers );
2434        
2435        //now tie it all together
2436
Select select = new Select( getFactory().getDialect() );
2437        select.setSelectClause( selectFragment.toFragmentString().substring( 2 ) );
2438        select.setFromClause( from );
2439        select.setWhereClause( where );
2440        select.setOuterJoins( jf.toFromFragmentString(), jf.toWhereFragmentString() );
2441        if ( getFactory().getSettings().isCommentsEnabled() ) {
2442            select.setComment( "sequential select " + getEntityName() );
2443        }
2444        return select.toStatementString();
2445    }
2446
2447    private String JavaDoc getRootAlias() {
2448        return StringHelper.generateAlias( getEntityName() );
2449    }
2450    
2451    protected void postConstruct(Mapping mapping) throws MappingException {
2452        initPropertyPaths(mapping);
2453        
2454        //insert/update/delete SQL
2455
final int joinSpan = getTableSpan();
2456        sqlDeleteStrings = new String JavaDoc[joinSpan];
2457        sqlInsertStrings = new String JavaDoc[joinSpan];
2458        sqlUpdateStrings = new String JavaDoc[joinSpan];
2459        sqlLazyUpdateStrings = new String JavaDoc[joinSpan];
2460
2461        sqlUpdateByRowIdString = rowIdName == null ?
2462                null :
2463                generateUpdateString( getPropertyUpdateability(), 0, true );
2464        sqlLazyUpdateByRowIdString = rowIdName == null ?
2465                null :
2466                generateUpdateString( getNonLazyPropertyUpdateability(), 0, true );
2467
2468        for ( int j = 0; j < joinSpan; j++ ) {
2469            sqlInsertStrings[j] = customSQLInsert[j] == null ?
2470                    generateInsertString( getPropertyInsertability(), j ) :
2471                    customSQLInsert[j];
2472            sqlUpdateStrings[j] = customSQLUpdate[j] == null ?
2473                    generateUpdateString( getPropertyUpdateability(), j, false ) :
2474                    customSQLUpdate[j];
2475            sqlLazyUpdateStrings[j] = customSQLUpdate[j] == null ?
2476                    generateUpdateString( getNonLazyPropertyUpdateability(), j, false ) :
2477                    customSQLUpdate[j];
2478            sqlDeleteStrings[j] = customSQLDelete[j] == null ?
2479                    generateDeleteString( j ) :
2480                    customSQLDelete[j];
2481        }
2482
2483        tableHasColumns = new boolean[joinSpan];
2484        for ( int j = 0; j < joinSpan; j++ ) {
2485            tableHasColumns[j] = sqlUpdateStrings[j] != null;
2486        }
2487        
2488        //select SQL
2489
sqlSnapshotSelectString = generateSnapshotSelectString();
2490        sqlLazySelectString = generateLazySelectString();
2491        sqlVersionSelectString = generateSelectVersionString();
2492        if ( isIdentifierAssignedByInsert() ) {
2493            sqlIdentityInsertString = customSQLInsert[0] == null ?
2494                    generateInsertString( true, getPropertyInsertability() ) :
2495                    customSQLInsert[0];
2496        }
2497        else {
2498            sqlIdentityInsertString = null;
2499        }
2500
2501        logStaticSQL();
2502        
2503    }
2504
2505    public void postInstantiate() throws MappingException {
2506
2507        createLoaders();
2508        createUniqueKeyLoaders();
2509        createQueryLoader();
2510
2511    }
2512
2513    private void createLoaders() {
2514        loaders.put( LockMode.NONE, createEntityLoader( LockMode.NONE ) );
2515
2516        UniqueEntityLoader readLoader = createEntityLoader( LockMode.READ );
2517        loaders.put( LockMode.READ, readLoader );
2518        
2519        //TODO: inexact, what we really need to know is: are any outer joins used?
2520
boolean disableForUpdate = getSubclassTableSpan() > 1 &&
2521                hasSubclasses() &&
2522                !getFactory().getDialect().supportsOuterJoinForUpdate();
2523
2524        loaders.put( LockMode.UPGRADE,
2525                disableForUpdate ? readLoader : createEntityLoader( LockMode.UPGRADE ) );
2526        loaders.put( LockMode.UPGRADE_NOWAIT,
2527                disableForUpdate ? readLoader : createEntityLoader( LockMode.UPGRADE_NOWAIT ) );
2528    }
2529
2530    protected void createQueryLoader() {
2531        if ( loaderName != null ) queryLoader = new NamedQueryLoader( loaderName, this );
2532    }
2533
2534    /**
2535     * Load an instance using either the <tt>forUpdateLoader</tt> or the outer joining <tt>loader</tt>,
2536     * depending upon the value of the <tt>lock</tt> parameter
2537     */

2538    public Object JavaDoc load(Serializable JavaDoc id, Object JavaDoc optionalObject, LockMode lockMode, SessionImplementor session)
2539            throws HibernateException {
2540
2541        if ( log.isTraceEnabled() ) {
2542            log.trace( "Materializing entity: " + MessageHelper.infoString( this, id, getFactory() ) );
2543        }
2544
2545        final UniqueEntityLoader loader = getAppropriateLoader( lockMode, session.getEnabledFilters() );
2546        return loader.load( id, optionalObject, session );
2547    }
2548
2549    private UniqueEntityLoader getAppropriateLoader(LockMode lockMode, Map JavaDoc enabledFilters) {
2550        if ( queryLoader != null ) {
2551            return queryLoader;
2552        }
2553        else if ( enabledFilters == null || enabledFilters.isEmpty() ) {
2554            return (UniqueEntityLoader) loaders.get( lockMode );
2555        }
2556        else {
2557            return createEntityLoader( lockMode, enabledFilters );
2558        }
2559    }
2560
2561    private boolean isAllNull(Object JavaDoc[] array, int tableNumber) {
2562        for ( int i = 0; i < array.length; i++ ) {
2563            if ( isPropertyOfTable( i, tableNumber ) && array[i] != null ) return false;
2564        }
2565        return true;
2566    }
2567    
2568    public boolean isSubclassPropertyNullable(int i) {
2569        return subclassPropertyNullabilityClosure[i];
2570    }
2571
2572    /**
2573     * Transform the array of property indexes to an array of booleans,
2574     * true when the property is dirty
2575     */

2576    protected final boolean[] getPropertiesToUpdate(final int[] dirtyProperties, final boolean hasDirtyCollection) {
2577        final boolean[] propsToUpdate = new boolean[ entityMetamodel.getPropertySpan() ];
2578        final boolean[] updateability = getPropertyUpdateability(); //no need to check laziness, dirty checking handles that
2579
for ( int j = 0; j < dirtyProperties.length; j++ ) {
2580            int property = dirtyProperties[j];
2581            if ( updateability[property] ) propsToUpdate[property] = true;
2582        }
2583        if ( isVersioned() ) {
2584            propsToUpdate[ getVersionProperty() ] =
2585                Versioning.isVersionIncrementRequired( dirtyProperties, hasDirtyCollection, getPropertyVersionability() );
2586        }
2587        return propsToUpdate;
2588    }
2589
2590    /**
2591     * Transform the array of property indexes to an array of booleans,
2592     * true when the property is insertable and non-null
2593     */

2594    protected boolean[] getPropertiesToInsert(Object JavaDoc[] fields) {
2595        boolean[] notNull = new boolean[fields.length];
2596        boolean[] insertable = getPropertyInsertability();
2597        for ( int i = 0; i < fields.length; i++ ) notNull[i] = insertable[i] && fields[i] != null;
2598        return notNull;
2599    }
2600
2601    /**
2602     * Locate the property-indices of all properties considered to be dirty.
2603     *
2604     * @param currentState The current state of the entity (the state to be checked).
2605     * @param previousState The previous state of the entity (the state to be checked against).
2606     * @param entity The entity for which we are checking state dirtiness.
2607     * @param session The session in which the check is ccurring.
2608     * @return <tt>null</tt> or the indices of the dirty properties
2609     * @throws HibernateException
2610     */

2611    public int[] findDirty(Object JavaDoc[] currentState, Object JavaDoc[] previousState, Object JavaDoc entity, SessionImplementor session)
2612    throws HibernateException {
2613        int[] props = TypeFactory.findDirty(
2614                entityMetamodel.getProperties(),
2615                currentState,
2616                previousState,
2617                hasUninitializedLazyProperties( entity, session.getEntityMode() ),
2618                session
2619            );
2620        if ( props == null ) {
2621            return null;
2622        }
2623        else {
2624            logDirtyProperties( props );
2625            return props;
2626        }
2627    }
2628
2629    /**
2630     * Locate the property-indices of all properties considered to be dirty.
2631     *
2632     * @param old The old state of the entity.
2633     * @param current The current state of the entity.
2634     * @param entity The entity for which we are checking state modification.
2635     * @param session The session in which the check is ccurring.
2636     * @return <tt>null</tt> or the indices of the modified properties
2637     * @throws HibernateException
2638     */

2639    public int[] findModified(Object JavaDoc[] old, Object JavaDoc[] current, Object JavaDoc entity, SessionImplementor session)
2640    throws HibernateException {
2641        int[] props = TypeFactory.findModified(
2642                entityMetamodel.getProperties(),
2643                current,
2644                old,
2645                hasUninitializedLazyProperties( entity, session.getEntityMode() ),
2646                session
2647            );
2648        if ( props == null ) {
2649            return null;
2650        }
2651        else {
2652            logDirtyProperties( props );
2653            return props;
2654        }
2655    }
2656
2657    /**
2658     * Which properties appear in the SQL update?
2659     * (Initialized, updateable ones!)
2660     */

2661    protected boolean[] getPropertyUpdateability(Object JavaDoc entity, EntityMode entityMode) {
2662        return hasUninitializedLazyProperties( entity, entityMode ) ?
2663                getNonLazyPropertyUpdateability() :
2664                getPropertyUpdateability();
2665    }
2666
2667    private void logDirtyProperties(int[] props) {
2668        if ( log.isTraceEnabled() ) {
2669            for ( int i = 0; i < props.length; i++ ) {
2670                String JavaDoc propertyName = entityMetamodel.getProperties()[ props[i] ].getName();
2671                log.trace( StringHelper.qualify( getEntityName(), propertyName ) + " is dirty" );
2672            }
2673        }
2674    }
2675
2676    protected EntityTuplizer getTuplizer(SessionImplementor session) {
2677        return getTuplizer( session.getEntityMode() );
2678    }
2679
2680    protected EntityTuplizer getTuplizer(EntityMode entityMode) {
2681        return entityMetamodel.getTuplizer( entityMode );
2682    }
2683
2684    public SessionFactoryImplementor getFactory() {
2685        return factory;
2686    }
2687
2688    protected EntityMetamodel getEntityMetamodel() {
2689        return entityMetamodel;
2690    }
2691
2692    public boolean hasCache() {
2693        return cache != null;
2694    }
2695
2696    public CacheConcurrencyStrategy getCache() {
2697        return cache;
2698    }
2699
2700    public CacheEntryStructure getCacheEntryStructure() {
2701        return cacheEntryStructure;
2702    }
2703
2704    // temporary ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2705
public final String JavaDoc getEntityName() {
2706        return entityMetamodel.getName();
2707    }
2708    
2709    public EntityType getEntityType() {
2710        return entityMetamodel.getEntityType();
2711    }
2712
2713    private String JavaDoc getSubclassEntityName(Class JavaDoc clazz) {
2714        return ( String JavaDoc ) entityNameBySubclass.get( clazz );
2715    }
2716
2717    public boolean isPolymorphic() {
2718        return entityMetamodel.isPolymorphic();
2719    }
2720
2721    public boolean isInherited() {
2722        return entityMetamodel.isInherited();
2723    }
2724
2725    public boolean hasCascades() {
2726        return entityMetamodel.hasCascades();
2727    }
2728
2729    public boolean hasIdentifierProperty() {
2730        return !entityMetamodel.getIdentifierProperty().isVirtual();
2731    }
2732
2733    public VersionType getVersionType() {
2734        return ( VersionType ) locateVersionType();
2735    }
2736
2737    private Type locateVersionType() {
2738        return entityMetamodel.getVersionProperty() == null ?
2739                null :
2740                entityMetamodel.getVersionProperty().getType();
2741    }
2742
2743    public int getVersionProperty() {
2744        return entityMetamodel.getVersionPropertyIndex();
2745    }
2746
2747    public boolean isVersioned() {
2748        return entityMetamodel.isVersioned();
2749    }
2750
2751    public boolean isIdentifierAssignedByInsert() {
2752        return entityMetamodel.getIdentifierProperty().isIdentifierAssignedByInsert();
2753    }
2754
2755    protected boolean hasLazyProperties() {
2756        return entityMetamodel.hasLazyProperties();
2757    }
2758
2759// public boolean hasUninitializedLazyProperties(Object entity) {
2760
// if ( hasLazyProperties() ) {
2761
// InterceptFieldCallback callback = ( ( InterceptFieldEnabled ) entity ).getInterceptFieldCallback();
2762
// return callback != null && !( ( FieldInterceptor ) callback ).isInitialized();
2763
// }
2764
// else {
2765
// return false;
2766
// }
2767
// }
2768

2769    public void afterReassociate(Object JavaDoc entity, SessionImplementor session) {
2770        //if ( hasLazyProperties() ) {
2771
if ( entity instanceof InterceptFieldEnabled ) {
2772            FieldInterceptor interceptor = FieldInterceptor.getFieldInterceptor(entity);
2773            if ( interceptor != null ) {
2774                interceptor.setSession(session);
2775            }
2776            else {
2777                FieldInterceptor fieldInterceptor = FieldInterceptor.initFieldInterceptor(
2778                        entity,
2779                        getEntityName(),
2780                        session,
2781                        null
2782                    );
2783                fieldInterceptor.dirty();
2784            }
2785        }
2786    }
2787
2788    public Boolean JavaDoc isTransient(Object JavaDoc entity, SessionImplementor session) throws HibernateException {
2789        final Serializable JavaDoc id;
2790        if ( hasIdentifierPropertyOrEmbeddedCompositeIdentifier() ) {
2791            id = getIdentifier( entity, session.getEntityMode() );
2792        }
2793        else {
2794            id = null;
2795        }
2796        // we *always* assume an instance with a null
2797
// identifier or no identifier property is unsaved!
2798
if ( id == null ) return Boolean.TRUE;
2799
2800        // check the version unsaved-value, if appropriate
2801
final Object JavaDoc version = getVersion( entity, session.getEntityMode() );
2802        if ( isVersioned() ) {
2803            // let this take precedence if defined, since it works for
2804
// assigned identifiers
2805
Boolean JavaDoc result = entityMetamodel.getVersionProperty()
2806                    .getUnsavedValue().isUnsaved( version );
2807            if ( result != null ) return result;
2808        }
2809
2810        // check the id unsaved-value
2811
Boolean JavaDoc result = entityMetamodel.getIdentifierProperty()
2812                .getUnsavedValue().isUnsaved( id );
2813        if ( result != null ) return result;
2814
2815        // check to see if it is in the second-level cache
2816
if ( hasCache() ) {
2817            CacheKey ck = new CacheKey(
2818                    id,
2819                    getIdentifierType(),
2820                    getRootEntityName(),
2821                    session.getEntityMode(),
2822                    session.getFactory()
2823                );
2824            if ( getCache().get( ck, session.getTimestamp() ) != null ) {
2825                return Boolean.FALSE;
2826            }
2827        }
2828
2829        return null;
2830    }
2831
2832    public boolean hasCollections() {
2833        return entityMetamodel.hasCollections();
2834    }
2835
2836    public boolean hasMutableProperties() {
2837        return entityMetamodel.hasMutableProperties();
2838    }
2839    
2840    public boolean isMutable() {
2841        return entityMetamodel.isMutable();
2842    }
2843
2844    public boolean isAbstract() {
2845        return entityMetamodel.isAbstract();
2846    }
2847
2848    public boolean hasSubclasses() {
2849        return entityMetamodel.hasSubclasses();
2850    }
2851
2852    public boolean hasProxy() {
2853        return entityMetamodel.isLazy();
2854    }
2855
2856    public IdentifierGenerator getIdentifierGenerator() throws HibernateException {
2857        return entityMetamodel.getIdentifierProperty().getIdentifierGenerator();
2858    }
2859
2860    public String JavaDoc getRootEntityName() {
2861        return entityMetamodel.getRootName();
2862    }
2863
2864    public ClassMetadata getClassMetadata() {
2865        return this;
2866    }
2867
2868    public String JavaDoc getMappedSuperclass() {
2869        return entityMetamodel.getSuperclass();
2870    }
2871
2872    public boolean isExplicitPolymorphism() {
2873        return entityMetamodel.isExplicitPolymorphism();
2874    }
2875
2876    protected boolean useDynamicUpdate() {
2877        return entityMetamodel.isDynamicUpdate();
2878    }
2879
2880    protected boolean useDynamicInsert() {
2881        return entityMetamodel.isDynamicInsert();
2882    }
2883
2884    protected boolean hasEmbeddedIdentifier() {
2885        return entityMetamodel.getIdentifierProperty().isEmbedded();
2886    }
2887
2888    public boolean hasIdentifierPropertyOrEmbeddedCompositeIdentifier() {
2889        return hasIdentifierProperty() || hasEmbeddedIdentifier();
2890    }
2891
2892    public String JavaDoc[] getKeyColumnNames() {
2893        return getIdentifierColumnNames();
2894    }
2895
2896    public String JavaDoc getName() {
2897        return getEntityName();
2898    }
2899
2900    public boolean isCollection() {
2901        return false;
2902    }
2903
2904    public boolean consumesEntityAlias() {
2905        return true;
2906    }
2907
2908    public boolean consumesCollectionAlias() {
2909        return false;
2910    }
2911
2912    public Type getPropertyType(String JavaDoc propertyName) throws MappingException {
2913        return propertyMapping.toType(propertyName);
2914    }
2915
2916    public Type getType() {
2917        return entityMetamodel.getEntityType();
2918    }
2919
2920    public boolean isSelectBeforeUpdateRequired() {
2921        return entityMetamodel.isSelectBeforeUpdate();
2922    }
2923
2924    protected final int optimisticLockMode() {
2925        return entityMetamodel.getOptimisticLockMode();
2926    }
2927
2928    public Object JavaDoc createProxy(Serializable JavaDoc id, SessionImplementor session) throws HibernateException {
2929        return entityMetamodel.getTuplizer( session.getEntityMode() )
2930                .createProxy( id, session );
2931    }
2932
2933    public String JavaDoc toString() {
2934        return StringHelper.unqualify( getClass().getName() ) +
2935                '(' + entityMetamodel.getName() + ')';
2936    }
2937
2938    public final String JavaDoc selectFragment(
2939            Joinable rhs,
2940            String JavaDoc rhsAlias,
2941            String JavaDoc lhsAlias,
2942            String JavaDoc entitySuffix,
2943            String JavaDoc collectionSuffix,
2944            boolean includeCollectionColumns) {
2945        return selectFragment( lhsAlias, entitySuffix );
2946    }
2947
2948    protected boolean isInstrumented(EntityMode entityMode) {
2949        EntityTuplizer tuplizer = entityMetamodel.getTuplizerOrNull(entityMode);
2950        return tuplizer!=null && tuplizer.isInstrumented();
2951    }
2952
2953    public void afterInitialize(Object JavaDoc entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
2954        getTuplizer( session ).afterInitialize( entity, lazyPropertiesAreUnfetched, session );
2955    }
2956
2957    public String JavaDoc[] getPropertyNames() {
2958        return entityMetamodel.getPropertyNames();
2959    }
2960
2961    public Type[] getPropertyTypes() {
2962        return entityMetamodel.getPropertyTypes();
2963    }
2964
2965    public boolean[] getPropertyLaziness() {
2966        return entityMetamodel.getPropertyLaziness();
2967    }
2968
2969    public boolean[] getPropertyUpdateability() {
2970        return entityMetamodel.getPropertyUpdateability();
2971    }
2972
2973    public boolean[] getPropertyCheckability() {
2974        return entityMetamodel.getPropertyCheckability();
2975    }
2976
2977    public boolean[] getNonLazyPropertyUpdateability() {
2978        return entityMetamodel.getNonlazyPropertyUpdateability();
2979    }
2980
2981    public boolean[] getPropertyInsertability() {
2982        return entityMetamodel.getPropertyInsertability();
2983    }
2984
2985    public boolean[] getPropertyNullability() {
2986        return entityMetamodel.getPropertyNullability();
2987    }
2988
2989    public boolean[] getPropertyVersionability() {
2990        return entityMetamodel.getPropertyVersionability();
2991    }
2992
2993    public CascadeStyle[] getPropertyCascadeStyles() {
2994        return entityMetamodel.getCascadeStyles();
2995    }
2996
2997    public final Class JavaDoc getMappedClass(EntityMode entityMode) {
2998        Tuplizer tup = entityMetamodel.getTuplizerOrNull(entityMode);
2999        return tup==null ? null : tup.getMappedClass();
3000    }
3001
3002    public boolean implementsLifecycle(EntityMode entityMode) {
3003        return getTuplizer( entityMode ).isLifecycleImplementor();
3004    }
3005
3006    public boolean implementsValidatable(EntityMode entityMode) {
3007        return getTuplizer( entityMode ).isValidatableImplementor();
3008    }
3009
3010    public Class JavaDoc getConcreteProxyClass(EntityMode entityMode) {
3011        return getTuplizer( entityMode ).getConcreteProxyClass();
3012    }
3013
3014    public void setPropertyValues(Object JavaDoc object, Object JavaDoc[] values, EntityMode entityMode)
3015            throws HibernateException {
3016        getTuplizer( entityMode ).setPropertyValues( object, values );
3017    }
3018
3019    public void setPropertyValue(Object JavaDoc object, int i, Object JavaDoc value, EntityMode entityMode)
3020            throws HibernateException {
3021        getTuplizer( entityMode ).setPropertyValue( object, i, value );
3022    }
3023
3024    public Object JavaDoc[] getPropertyValues(Object JavaDoc object, EntityMode entityMode)
3025            throws HibernateException {
3026        return getTuplizer( entityMode ).getPropertyValues( object );
3027    }
3028
3029    public Object JavaDoc getPropertyValue(Object JavaDoc object, int i, EntityMode entityMode)
3030            throws HibernateException {
3031        return getTuplizer( entityMode ).getPropertyValue( object , i );
3032    }
3033
3034    public Object JavaDoc getPropertyValue(Object JavaDoc object, String JavaDoc propertyName, EntityMode entityMode)
3035            throws HibernateException {
3036        return getTuplizer( entityMode ).getPropertyValue( object, propertyName );
3037    }
3038    
3039    public Serializable JavaDoc getIdentifier(Object JavaDoc object, EntityMode entityMode)
3040            throws HibernateException {
3041        return getTuplizer( entityMode ).getIdentifier( object );
3042    }
3043
3044    public void setIdentifier(Object JavaDoc object, Serializable JavaDoc id, EntityMode entityMode)
3045            throws HibernateException {
3046        getTuplizer( entityMode ).setIdentifier( object, id );
3047    }
3048
3049    public Object JavaDoc getVersion(Object JavaDoc object, EntityMode entityMode)
3050            throws HibernateException {
3051        return getTuplizer( entityMode ).getVersion( object );
3052    }
3053
3054    public Object JavaDoc instantiate(Serializable JavaDoc id, EntityMode entityMode)
3055            throws HibernateException {
3056        return getTuplizer( entityMode ).instantiate( id );
3057    }
3058
3059    public boolean isInstance(Object JavaDoc object, EntityMode entityMode) {
3060        return getTuplizer( entityMode ).isInstance( object );
3061    }
3062
3063    public boolean hasUninitializedLazyProperties(Object JavaDoc object, EntityMode entityMode) {
3064        return getTuplizer( entityMode ).hasUninitializedLazyProperties( object );
3065    }
3066
3067    public void resetIdentifier(Object JavaDoc entity, Serializable JavaDoc currentId, Object JavaDoc currentVersion, EntityMode entityMode) {
3068        getTuplizer( entityMode ).resetIdentifier( entity, currentId, currentVersion );
3069    }
3070
3071    public EntityPersister getSubclassEntityPersister(Object JavaDoc instance, SessionFactoryImplementor factory, EntityMode entityMode) {
3072        if ( !hasSubclasses() ) {
3073            return this;
3074        }
3075        else {
3076            Class JavaDoc clazz = instance.getClass();
3077            if ( clazz == getMappedClass( entityMode ) ) {
3078                return this;
3079            }
3080            else {
3081                String JavaDoc subclassEntityName = getSubclassEntityName( clazz );
3082                if ( subclassEntityName == null ) {
3083                    throw new HibernateException( "instance not of expected entity type: " + getEntityName() );
3084                }
3085                else {
3086                    return factory.getEntityPersister( subclassEntityName );
3087                }
3088            }
3089        }
3090    }
3091
3092    public EntityMode guessEntityMode(Object JavaDoc object) {
3093        return entityMetamodel.guessEntityMode(object);
3094    }
3095
3096    public boolean isMultiTable() {
3097        return false;
3098    }
3099
3100    public String JavaDoc getTemporaryIdTableName() {
3101        return temporaryIdTableName;
3102    }
3103
3104    public String JavaDoc getTemporaryIdTableDDL() {
3105        return temporaryIdTableDDL;
3106    }
3107
3108    protected int getPropertySpan() {
3109        return entityMetamodel.getPropertySpan();
3110    }
3111
3112    public Object JavaDoc[] getPropertyValuesToInsert(Object JavaDoc object, Map JavaDoc mergeMap, SessionImplementor session) throws HibernateException {
3113        return getTuplizer( session.getEntityMode() ).getPropertyValuesToInsert( object, mergeMap, session );
3114    }
3115
3116    public String JavaDoc getIdentifierPropertyName() {
3117        return entityMetamodel.getIdentifierProperty().getName();
3118    }
3119
3120    public Type getIdentifierType() {
3121        return entityMetamodel.getIdentifierProperty().getType();
3122    }
3123    
3124    public boolean hasSubselectLoadableCollections() {
3125        return hasSubselectLoadableCollections;
3126    }
3127    
3128    public int[] getNaturalIdentifierProperties() {
3129        return entityMetamodel.getNaturalIdentifierProperties();
3130    }
3131    
3132    public boolean hasNaturalIdentifier() {
3133        return entityMetamodel.hasNaturalIdentifier();
3134    }
3135    
3136    public void setPropertyValue(Object JavaDoc object, String JavaDoc propertyName, Object JavaDoc value, EntityMode entityMode)
3137            throws HibernateException {
3138        getTuplizer( entityMode ).setPropertyValue( object, propertyName, value );
3139    }
3140    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3141

3142}
3143
Popular Tags