1 package org.hibernate.persister.entity; 3 4 import java.io.Serializable ; 5 import java.util.HashMap ; 6 import java.util.HashSet ; 7 import java.util.Iterator ; 8 import java.util.Map ; 9 import java.util.ArrayList ; 10 11 import org.hibernate.AssertionFailure; 12 import org.hibernate.Hibernate; 13 import org.hibernate.HibernateException; 14 import org.hibernate.LockMode; 15 import org.hibernate.MappingException; 16 import org.hibernate.cache.CacheConcurrencyStrategy; 17 import org.hibernate.cfg.Settings; 18 import org.hibernate.dialect.Dialect; 19 import org.hibernate.engine.Mapping; 20 import org.hibernate.engine.SessionFactoryImplementor; 21 import org.hibernate.id.IdentityGenerator; 22 import org.hibernate.mapping.Column; 23 import org.hibernate.mapping.PersistentClass; 24 import org.hibernate.mapping.Subclass; 25 import org.hibernate.mapping.Table; 26 import org.hibernate.sql.SelectFragment; 27 import org.hibernate.sql.SimpleSelect; 28 import org.hibernate.type.Type; 29 import org.hibernate.util.ArrayHelper; 30 import org.hibernate.util.JoinedIterator; 31 import org.hibernate.util.SingletonIterator; 32 33 39 public class UnionSubclassEntityPersister extends BasicEntityPersister { 40 41 private final String subquery; 43 private final String tableName; 44 private final String [] subclassClosure; 46 private final String [] spaces; 47 private final String [] subclassSpaces; 48 private final String discriminatorSQLValue; 49 private final Map subclassByDiscriminatorValue = new HashMap (); 50 51 private final String [] constraintOrderedTableNames; 52 private final String [][] constraintOrderedKeyColumnNames; 53 54 56 public UnionSubclassEntityPersister( 57 final PersistentClass persistentClass, 58 final CacheConcurrencyStrategy cache, 59 final SessionFactoryImplementor factory, 60 final Mapping mapping) 61 throws HibernateException { 62 63 super(persistentClass, cache, factory); 64 65 if ( getIdentifierGenerator() instanceof IdentityGenerator ) { 66 throw new MappingException( 67 "Cannot use identity column key generation with <union-subclass> mapping for: " + 68 getEntityName() 69 ); 70 } 71 72 74 tableName = persistentClass.getTable().getQualifiedName( 75 factory.getDialect(), 76 factory.getSettings().getDefaultCatalogName(), 77 factory.getSettings().getDefaultSchemaName() 78 ); 79 84 85 insertCallable = new boolean[] { persistentClass.isCustomInsertCallable() }; 87 updateCallable = new boolean[] { persistentClass.isCustomUpdateCallable() }; 88 deleteCallable = new boolean[] { persistentClass.isCustomDeleteCallable() }; 89 90 customSQLInsert = new String [] { persistentClass.getCustomSQLInsert() }; 91 customSQLUpdate = new String [] { persistentClass.getCustomSQLUpdate() }; 92 customSQLDelete = new String [] { persistentClass.getCustomSQLDelete() }; 93 94 discriminatorSQLValue = String.valueOf( persistentClass.getSubclassId() ); 95 96 98 int subclassSpan = persistentClass.getSubclassSpan() + 1; 99 subclassClosure = new String [subclassSpan]; 100 subclassClosure[0] = getEntityName(); 101 102 subclassByDiscriminatorValue.put( 104 new Integer ( persistentClass.getSubclassId() ), 105 persistentClass.getEntityName() 106 ); 107 if ( persistentClass.isPolymorphic() ) { 108 Iterator iter = persistentClass.getSubclassIterator(); 109 int k=1; 110 while ( iter.hasNext() ) { 111 Subclass sc = (Subclass) iter.next(); 112 subclassClosure[k++] = sc.getEntityName(); 113 subclassByDiscriminatorValue.put( new Integer ( sc.getSubclassId() ), sc.getEntityName() ); 114 } 115 } 116 117 121 int spacesSize = 1 + persistentClass.getSynchronizedTables().size(); 122 spaces = new String [spacesSize]; 123 spaces[0] = tableName; 124 Iterator iter = persistentClass.getSynchronizedTables().iterator(); 125 for ( int i=1; i<spacesSize; i++ ) { 126 spaces[i] = (String ) iter.next(); 127 } 128 129 HashSet subclassTables = new HashSet (); 130 iter = persistentClass.getSubclassTableClosureIterator(); 131 while ( iter.hasNext() ) { 132 Table table = (Table) iter.next(); 133 subclassTables.add( table.getQualifiedName( 134 factory.getDialect(), 135 factory.getSettings().getDefaultCatalogName(), 136 factory.getSettings().getDefaultSchemaName() 137 ) ); 138 } 139 subclassSpaces = ArrayHelper.toStringArray(subclassTables); 140 141 subquery = generateSubquery(persistentClass, mapping); 142 143 if ( isMultiTable() ) { 144 int idColumnSpan = getIdentifierColumnSpan(); 145 ArrayList tableNames = new ArrayList (); 146 ArrayList keyColumns = new ArrayList (); 147 iter = persistentClass.getSubclassTableClosureIterator(); 148 while ( iter.hasNext() ) { 149 Table tab = ( Table ) iter.next(); 150 if ( !tab.isAbstractUnionTable() ) { 151 String tableName = tab.getQualifiedName( 152 factory.getDialect(), 153 factory.getSettings().getDefaultCatalogName(), 154 factory.getSettings().getDefaultSchemaName() 155 ); 156 tableNames.add( tableName ); 157 String [] key = new String [idColumnSpan]; 158 Iterator citer = tab.getPrimaryKey().getColumnIterator(); 159 for ( int k=0; k<idColumnSpan; k++ ) { 160 key[k] = ( ( Column ) citer.next() ).getQuotedName( factory.getDialect() ); 161 } 162 keyColumns.add( key ); 163 } 164 } 165 166 constraintOrderedTableNames = ArrayHelper.toStringArray( tableNames ); 167 constraintOrderedKeyColumnNames = ArrayHelper.to2DStringArray( keyColumns ); 168 } 169 else { 170 constraintOrderedTableNames = new String [] { tableName }; 171 constraintOrderedKeyColumnNames = new String [][] { getIdentifierColumnNames() }; 172 } 173 174 initLockers(); 175 176 initSubclassPropertyAliasesMap(persistentClass); 177 178 postConstruct(mapping); 179 180 } 181 182 public Serializable [] getQuerySpaces() { 183 return subclassSpaces; 184 } 185 186 public String getTableName() { 187 return subquery; 188 } 189 190 public Type getDiscriminatorType() { 191 return Hibernate.INTEGER; 192 } 193 194 public String getDiscriminatorSQLValue() { 195 return discriminatorSQLValue; 196 } 197 198 public String [] getSubclassClosure() { 199 return subclassClosure; 200 } 201 202 public String getSubclassForDiscriminatorValue(Object value) { 203 return (String ) subclassByDiscriminatorValue.get(value); 204 } 205 206 public Serializable [] getPropertySpaces() { 207 return spaces; 208 } 209 210 protected boolean isDiscriminatorFormula() { 211 return false; 212 } 213 214 217 protected String generateSelectString(LockMode lockMode) { 218 SimpleSelect select = new SimpleSelect( getFactory().getDialect() ) 219 .setLockMode(lockMode) 220 .setTableName( getTableName() ) 221 .addColumns( getIdentifierColumnNames() ) 222 .addColumns( 223 getSubclassColumnClosure(), 224 getSubclassColumnAliasClosure(), 225 getSubclassColumnLazyiness() 226 ) 227 .addColumns( 228 getSubclassFormulaClosure(), 229 getSubclassFormulaAliasClosure(), 230 getSubclassFormulaLazyiness() 231 ); 232 if ( hasSubclasses() ) { 234 if ( isDiscriminatorFormula() ) { 235 select.addColumn( getDiscriminatorFormula(), getDiscriminatorAlias() ); 236 } 237 else { 238 select.addColumn( getDiscriminatorColumnName(), getDiscriminatorAlias() ); 239 } 240 } 241 if ( getFactory().getSettings().isCommentsEnabled() ) { 242 select.setComment( "load " + getEntityName() ); 243 } 244 return select.addCondition( getIdentifierColumnNames(), "=?" ).toStatementString(); 245 } 246 247 protected String getDiscriminatorFormula() { 248 return null; 249 } 250 251 protected String getTableName(int j) { 252 return tableName; 253 } 254 255 protected String [] getKeyColumns(int j) { 256 return getIdentifierColumnNames(); 257 } 258 259 protected boolean isTableCascadeDeleteEnabled(int j) { 260 return false; 261 } 262 263 protected boolean isPropertyOfTable(int property, int j) { 264 return true; 265 } 266 267 269 public String fromTableFragment(String name) { 270 return getTableName() + ' ' + name; 271 } 272 273 public String filterFragment(String name) { 274 return hasWhere() ? 275 " and " + getSQLWhereString(name) : 276 ""; 277 } 278 279 public String getSubclassPropertyTableName(int i) { 280 return getTableName(); } 282 283 protected void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) { 284 select.addColumn( name, getDiscriminatorColumnName(), getDiscriminatorAlias() ); 285 } 286 287 protected int[] getPropertyTableNumbersInSelect() { 288 return new int[ getPropertySpan() ]; 289 } 290 291 protected int getSubclassPropertyTableNumber(int i) { 292 return 0; 293 } 294 295 public int getSubclassPropertyTableNumber(String propertyName) { 296 return 0; 297 } 298 299 public boolean isMultiTable() { 300 return isAbstract() || hasSubclasses(); 302 } 303 304 public int getTableSpan() { 305 return 1; 306 } 307 308 protected int[] getSubclassColumnTableNumberClosure() { 309 return new int[ getSubclassColumnClosure().length ]; 310 } 311 312 protected int[] getSubclassFormulaTableNumberClosure() { 313 return new int[ getSubclassFormulaClosure().length ]; 314 } 315 316 protected boolean[] getTableHasColumns() { 317 return new boolean[] { true }; 318 } 319 320 protected int[] getPropertyTableNumbers() { 321 return new int[ getPropertySpan() ]; 322 } 323 324 protected String generateSubquery(PersistentClass model, Mapping mapping) { 325 326 Dialect dialect = getFactory().getDialect(); 327 Settings settings = getFactory().getSettings(); 328 329 if ( !model.hasSubclasses() ) { 330 return model.getTable().getQualifiedName( 331 dialect, 332 settings.getDefaultCatalogName(), 333 settings.getDefaultSchemaName() 334 ); 335 } 336 337 HashSet columns = new HashSet (); 338 Iterator titer = model.getSubclassTableClosureIterator(); 339 while ( titer.hasNext() ) { 340 Table table = (Table) titer.next(); 341 if ( !table.isAbstractUnionTable() ) { 342 Iterator citer = table.getColumnIterator(); 343 while ( citer.hasNext() ) columns.add( citer.next() ); 344 } 345 } 346 347 StringBuffer buf = new StringBuffer () 348 .append("( "); 349 350 Iterator siter = new JoinedIterator( 351 new SingletonIterator(model), 352 model.getSubclassIterator() 353 ); 354 355 while ( siter.hasNext() ) { 356 PersistentClass clazz = (PersistentClass) siter.next(); 357 Table table = clazz.getTable(); 358 if ( !table.isAbstractUnionTable() ) { 359 buf.append("select "); 361 Iterator citer = columns.iterator(); 362 while ( citer.hasNext() ) { 363 Column col = (Column) citer.next(); 364 if ( !table.containsColumn(col) ) { 365 int sqlType = col.getSqlTypeCode(mapping); 366 buf.append( dialect.getSelectClauseNullString(sqlType) ) 367 .append(" as "); 368 } 369 buf.append( col.getName() ); 370 buf.append(", "); 371 } 372 buf.append( clazz.getSubclassId() ) 373 .append(" as clazz_"); 374 buf.append(" from ") 375 .append( table.getQualifiedName( 376 dialect, 377 settings.getDefaultCatalogName(), 378 settings.getDefaultSchemaName() 379 ) ); 380 buf.append(" union "); 381 if ( dialect.supportsUnionAll() ) { 382 buf.append("all "); 383 } 384 } 385 } 386 387 if ( buf.length() > 2 ) { 388 buf.setLength( buf.length() - ( dialect.supportsUnionAll() ? 11 : 7 ) ); 390 } 391 392 return buf.append(" )").toString(); 393 } 394 395 protected String [] getSubclassTableKeyColumns(int j) { 396 if (j!=0) throw new AssertionFailure("only one table"); 397 return getIdentifierColumnNames(); 398 } 399 400 public String getSubclassTableName(int j) { 401 if (j!=0) throw new AssertionFailure("only one table"); 402 return tableName; 403 } 404 405 public int getSubclassTableSpan() { 406 return 1; 407 } 408 409 protected boolean isClassOrSuperclassTable(int j) { 410 if (j!=0) throw new AssertionFailure("only one table"); 411 return true; 412 } 413 414 public String getPropertyTableName(String propertyName) { 415 return getTableName(); 417 } 418 419 public String [] getConstraintOrderedTableNameClosure() { 420 return constraintOrderedTableNames; 421 } 422 423 public String [][] getContraintOrderedTableKeyColumnClosure() { 424 return constraintOrderedKeyColumnNames; 425 } 426 } 427 | Popular Tags |