KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > persister > collection > OneToManyPersister


1 //$Id: OneToManyPersister.java,v 1.15 2005/06/22 04:19:33 oneovthafew Exp $
2
package org.hibernate.persister.collection;
3
4 import java.io.Serializable JavaDoc;
5 import java.sql.CallableStatement JavaDoc;
6 import java.sql.PreparedStatement JavaDoc;
7 import java.sql.SQLException JavaDoc;
8 import java.sql.Types JavaDoc;
9 import java.util.Iterator JavaDoc;
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 /**
32  * Collection persister for one-to-many associations.
33  *
34  * @author Gavin King
35  */

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     /**
67      * Generate the SQL UPDATE that updates all the foreign keys to null
68      */

69     protected String JavaDoc 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     /**
88      * Generate the SQL UPDATE that updates a foreign key to a value
89      */

90     protected String JavaDoc generateInsertRowString() {
91         
92         Update update = new Update()
93                 .setTableName( qualifiedTableName )
94                 .addColumns( keyColumnNames );
95         
96         if ( hasIndex && !indexContainsFormula ) update.addColumns( indexColumnNames );
97         
98         //identifier collections not supported for 1-to-many
99
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     /**
108      * Not needed for one-to-many association
109      */

110     protected String JavaDoc generateUpdateRowString() {
111         return null;
112     }
113
114     /**
115      * Generate the SQL UPDATE that updates a particular row's foreign
116      * key to null
117      */

118     protected String JavaDoc 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         //use a combination of foreign key columns and pk columns, since
131
//the ordering of removal and addition is not guaranteed when
132
//a child moves from one parent to another
133
String JavaDoc[] 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 JavaDoc id, PersistentCollection collection, SessionImplementor session)
154             throws HibernateException {
155
156         // we finish all the "removes" first to take care of possible unique
157
// constraints and so that we can take better advantage of batching
158

159         try {
160             int count = 0;
161             if ( isRowDeleteEnabled() ) {
162                 // update removed rows fks to null
163
try {
164                     PreparedStatement JavaDoc st = null;
165                     int i = 0;
166     
167                     Iterator JavaDoc entries = collection.entries(this);
168                     int offset = 1;
169                     while ( entries.hasNext() ) {
170     
171                         Object JavaDoc entry = entries.next();
172                         if ( collection.needsUpdating( entry, i, elementType ) ) { // will still be issued when it used to be null
173
if ( st == null ) {
174                                 if ( isDeleteCallable() ) {
175                                     CallableStatement JavaDoc callstatement = session.getBatcher()
176                                         .prepareBatchCallableStatement( getSQLDeleteRowString() );
177                                     callstatement.registerOutParameter( offset++, Types.NUMERIC ); // TODO: should we require users to return number of update rows ? (we cant make it return this without changing collectionpersister interface)
178
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 JavaDoc sqle ) {
193                     session.getBatcher().abortBatch( sqle );
194                     throw sqle;
195                 }
196             }
197             
198             if ( isRowInsertEnabled() ) {
199                 // now update all changed or added rows fks
200
try {
201                     PreparedStatement JavaDoc st = null;
202                     int i = 0;
203                     Iterator JavaDoc entries = collection.entries(this);
204                     while ( entries.hasNext() ) {
205                         Object JavaDoc 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 JavaDoc sqle ) {
224                     session.getBatcher().abortBatch( sqle );
225                     throw sqle;
226                 }
227             }
228             
229             return count;
230         }
231         catch ( SQLException JavaDoc 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 JavaDoc selectFragment(
243             Joinable rhs,
244             String JavaDoc rhsAlias,
245             String JavaDoc lhsAlias,
246             String JavaDoc entitySuffix,
247             String JavaDoc collectionSuffix,
248             boolean includeCollectionColumns) {
249         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
250         if ( includeCollectionColumns ) {
251 // buf.append( selectFragment( lhsAlias, "" ) )//ignore suffix for collection columns!
252
buf.append( selectFragment( lhsAlias, collectionSuffix ) )
253                     .append( ", " );
254         }
255         OuterJoinLoadable ojl = ( OuterJoinLoadable ) getElementPersister();
256         return buf.append( ojl.selectFragment( lhsAlias, entitySuffix ) )//use suffix for the entity columns
257
.toString();
258     }
259
260     /**
261      * Create the <tt>OneToManyLoader</tt>
262      *
263      * @see org.hibernate.loader.collection.OneToManyLoader
264      */

265     protected CollectionInitializer createCollectionInitializer(java.util.Map JavaDoc enabledFilters) throws MappingException {
266         return BatchingCollectionInitializer.createBatchingOneToManyInitializer( this, batchSize, getFactory(), enabledFilters );
267     }
268
269     public String JavaDoc fromJoinFragment(String JavaDoc alias,
270                                    boolean innerJoin,
271                                    boolean includeSubclasses) {
272         return ( ( Joinable ) getElementPersister() ).fromJoinFragment( alias, innerJoin, includeSubclasses );
273     }
274
275     public String JavaDoc whereJoinFragment(String JavaDoc alias,
276                                     boolean innerJoin,
277                                     boolean includeSubclasses) {
278         return ( ( Joinable ) getElementPersister() ).whereJoinFragment( alias, innerJoin, includeSubclasses );
279     }
280
281     public String JavaDoc getTableName() {
282         return ( ( Joinable ) getElementPersister() ).getTableName();
283     }
284
285     public String JavaDoc filterFragment(String JavaDoc alias) throws MappingException {
286         String JavaDoc 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