1 package org.hibernate.persister.collection; 3 4 import java.io.Serializable ; 5 import java.sql.CallableStatement ; 6 import java.sql.PreparedStatement ; 7 import java.sql.SQLException ; 8 import java.sql.Types ; 9 import java.util.Iterator ; 10 11 import org.hibernate.HibernateException; 12 import org.hibernate.MappingException; 13 import org.hibernate.cache.CacheConcurrencyStrategy; 14 import org.hibernate.cache.CacheException; 15 import org.hibernate.cfg.Configuration; 16 import org.hibernate.collection.PersistentCollection; 17 import org.hibernate.engine.SessionFactoryImplementor; 18 import org.hibernate.engine.SessionImplementor; 19 import org.hibernate.engine.SubselectFetch; 20 import org.hibernate.exception.JDBCExceptionHelper; 21 import org.hibernate.loader.collection.BatchingCollectionInitializer; 22 import org.hibernate.loader.collection.CollectionInitializer; 23 import org.hibernate.loader.collection.SubselectOneToManyLoader; 24 import org.hibernate.mapping.Collection; 25 import org.hibernate.persister.entity.Joinable; 26 import org.hibernate.persister.entity.OuterJoinLoadable; 27 import org.hibernate.pretty.MessageHelper; 28 import org.hibernate.sql.Update; 29 import org.hibernate.util.ArrayHelper; 30 31 36 public class OneToManyPersister extends AbstractCollectionPersister { 37 38 private final boolean cascadeDeleteEnabled; 39 private final boolean keyIsNullable; 40 private final boolean keyIsUpdateable; 41 42 protected boolean isRowDeleteEnabled() { 43 return keyIsUpdateable && keyIsNullable; 44 } 45 46 protected boolean isRowInsertEnabled() { 47 return keyIsUpdateable; 48 } 49 50 public boolean isCascadeDeleteEnabled() { 51 return cascadeDeleteEnabled; 52 } 53 54 public OneToManyPersister(Collection collection, 55 CacheConcurrencyStrategy cache, 56 Configuration cfg, 57 SessionFactoryImplementor factory) 58 throws MappingException, CacheException { 59 super( collection, cache, cfg, factory ); 60 cascadeDeleteEnabled = collection.getKey().isCascadeDeleteEnabled() && 61 factory.getDialect().supportsCascadeDelete(); 62 keyIsNullable = collection.getKey().isNullable(); 63 keyIsUpdateable = collection.getKey().isUpdateable(); 64 } 65 66 69 protected String generateDeleteString() { 70 71 Update update = new Update() 72 .setTableName( qualifiedTableName ) 73 .addColumns( keyColumnNames, "null" ) 74 .setPrimaryKeyColumnNames( keyColumnNames ); 75 76 if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames, "null" ); 77 78 if ( hasWhere ) update.setWhere( sqlWhereString ); 79 80 if ( getFactory().getSettings().isCommentsEnabled() ) { 81 update.setComment( "delete one-to-many " + getRole() ); 82 } 83 84 return update.toStatementString(); 85 } 86 87 90 protected String generateInsertRowString() { 91 92 Update update = new Update() 93 .setTableName( qualifiedTableName ) 94 .addColumns( keyColumnNames ); 95 96 if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames ); 97 98 if ( getFactory().getSettings().isCommentsEnabled() ) { 100 update.setComment( "create one-to-many row " + getRole() ); 101 } 102 103 return update.setPrimaryKeyColumnNames( elementColumnNames ) 104 .toStatementString(); 105 } 106 107 110 protected String generateUpdateRowString() { 111 return null; 112 } 113 114 118 protected String generateDeleteRowString() { 119 120 Update update = new Update() 121 .setTableName( qualifiedTableName ) 122 .addColumns( keyColumnNames, "null" ); 123 124 if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames, "null" ); 125 126 if ( getFactory().getSettings().isCommentsEnabled() ) { 127 update.setComment( "delete one-to-many row " + getRole() ); 128 } 129 130 String [] rowSelectColumnNames = ArrayHelper.join(keyColumnNames, elementColumnNames); 134 return update.setPrimaryKeyColumnNames( rowSelectColumnNames ) 135 .toStatementString(); 136 } 137 138 public boolean consumesEntityAlias() { 139 return true; 140 } 141 public boolean consumesCollectionAlias() { 142 return true; 143 } 144 145 public boolean isOneToMany() { 146 return true; 147 } 148 149 public boolean isManyToMany() { 150 return false; 151 } 152 153 protected int doUpdateRows(Serializable id, PersistentCollection collection, SessionImplementor session) 154 throws HibernateException { 155 156 159 try { 160 int count = 0; 161 if ( isRowDeleteEnabled() ) { 162 try { 164 PreparedStatement st = null; 165 int i = 0; 166 167 Iterator entries = collection.entries(this); 168 int offset = 1; 169 while ( entries.hasNext() ) { 170 171 Object entry = entries.next(); 172 if ( collection.needsUpdating( entry, i, elementType ) ) { if ( st == null ) { 174 if ( isDeleteCallable() ) { 175 CallableStatement callstatement = session.getBatcher() 176 .prepareBatchCallableStatement( getSQLDeleteRowString() ); 177 callstatement.registerOutParameter( offset++, Types.NUMERIC ); st = callstatement; 179 } 180 else { 181 st = session.getBatcher().prepareBatchStatement( getSQLDeleteRowString() ); 182 } 183 } 184 int loc = writeKey( st, id, offset, session ); 185 writeElementToWhere( st, collection.getSnapshotElement(entry, i), loc, session ); 186 session.getBatcher().addToBatch( -1 ); 187 count++; 188 } 189 i++; 190 } 191 } 192 catch ( SQLException sqle ) { 193 session.getBatcher().abortBatch( sqle ); 194 throw sqle; 195 } 196 } 197 198 if ( isRowInsertEnabled() ) { 199 try { 201 PreparedStatement st = null; 202 int i = 0; 203 Iterator entries = collection.entries(this); 204 while ( entries.hasNext() ) { 205 Object entry = entries.next(); 206 int offset = 1; 207 if ( collection.needsUpdating( entry, i, elementType ) ) { 208 if ( st == null ) { 209 st = session.getBatcher() 210 .prepareBatchStatement( getSQLInsertRowString() ); 211 } 212 int loc = writeKey( st, id, offset, session ); 213 if ( hasIndex && !indexContainsFormula ) { 214 loc = writeIndexToWhere(st, collection.getIndex(entry, i, this), loc, session ); 215 } 216 writeElementToWhere( st, collection.getElement(entry), loc, session ); 217 session.getBatcher().addToBatch( 1 ); 218 count++; 219 } 220 i++; 221 } 222 } 223 catch ( SQLException sqle ) { 224 session.getBatcher().abortBatch( sqle ); 225 throw sqle; 226 } 227 } 228 229 return count; 230 } 231 catch ( SQLException sqle ) { 232 throw JDBCExceptionHelper.convert( 233 getSQLExceptionConverter(), 234 sqle, 235 "could not update collection rows: " + 236 MessageHelper.collectionInfoString( this, id, getFactory() ), 237 getSQLInsertRowString() 238 ); 239 } 240 } 241 242 public String selectFragment( 243 Joinable rhs, 244 String rhsAlias, 245 String lhsAlias, 246 String entitySuffix, 247 String collectionSuffix, 248 boolean includeCollectionColumns) { 249 StringBuffer buf = new StringBuffer (); 250 if ( includeCollectionColumns ) { 251 buf.append( selectFragment( lhsAlias, collectionSuffix ) ) 253 .append( ", " ); 254 } 255 OuterJoinLoadable ojl = ( OuterJoinLoadable ) getElementPersister(); 256 return buf.append( ojl.selectFragment( lhsAlias, entitySuffix ) ) .toString(); 258 } 259 260 265 protected CollectionInitializer createCollectionInitializer(java.util.Map enabledFilters) throws MappingException { 266 return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), enabledFilters ); 267 } 268 269 public String fromJoinFragment(String alias, 270 boolean innerJoin, 271 boolean includeSubclasses) { 272 return ( ( Joinable ) getElementPersister() ).fromJoinFragment( alias, innerJoin, includeSubclasses ); 273 } 274 275 public String whereJoinFragment(String alias, 276 boolean innerJoin, 277 boolean includeSubclasses) { 278 return ( ( Joinable ) getElementPersister() ).whereJoinFragment( alias, innerJoin, includeSubclasses ); 279 } 280 281 public String getTableName() { 282 return ( ( Joinable ) getElementPersister() ).getTableName(); 283 } 284 285 public String filterFragment(String alias) throws MappingException { 286 String result = super.filterFragment( alias ); 287 if ( getElementPersister() instanceof Joinable ) { 288 result += ( ( Joinable ) getElementPersister() ).oneToManyFilterFragment( alias ); 289 } 290 return result; 291 292 } 293 294 protected CollectionInitializer createSubselectInitializer(SubselectFetch subselect, SessionImplementor session) { 295 return new SubselectOneToManyLoader( this, 296 subselect.toSubselectString( getCollectionType().getLHSPropertyName() ), 297 subselect.getResult(), 298 subselect.getQueryParameters(), 299 session.getFactory(), 300 session.getEnabledFilters() ); 301 } 302 303 } 304 | Popular Tags |