001: //$Id: BasicCollectionPersister.java 10040 2006-06-22 19:51:43Z steve.ebersole@jboss.com $
002: package org.hibernate.persister.collection;
003:
004: import java.io.Serializable;
005: import java.sql.PreparedStatement;
006: import java.sql.SQLException;
007: import java.util.Iterator;
008:
009: import org.hibernate.HibernateException;
010: import org.hibernate.MappingException;
011: import org.hibernate.jdbc.Expectations;
012: import org.hibernate.jdbc.Expectation;
013: import org.hibernate.type.AssociationType;
014: import org.hibernate.persister.entity.Joinable;
015: import org.hibernate.cache.CacheConcurrencyStrategy;
016: import org.hibernate.cache.CacheException;
017: import org.hibernate.cfg.Configuration;
018: import org.hibernate.collection.PersistentCollection;
019: import org.hibernate.engine.SessionFactoryImplementor;
020: import org.hibernate.engine.SessionImplementor;
021: import org.hibernate.engine.SubselectFetch;
022: import org.hibernate.exception.JDBCExceptionHelper;
023: import org.hibernate.loader.collection.BatchingCollectionInitializer;
024: import org.hibernate.loader.collection.CollectionInitializer;
025: import org.hibernate.loader.collection.SubselectCollectionLoader;
026: import org.hibernate.mapping.Collection;
027: import org.hibernate.pretty.MessageHelper;
028: import org.hibernate.sql.Delete;
029: import org.hibernate.sql.Insert;
030: import org.hibernate.sql.Update;
031: import org.hibernate.sql.SelectFragment;
032: import org.hibernate.util.ArrayHelper;
033:
034: /**
035: * Collection persister for collections of values and many-to-many associations.
036: *
037: * @author Gavin King
038: */
039: public class BasicCollectionPersister extends
040: AbstractCollectionPersister {
041:
042: public boolean isCascadeDeleteEnabled() {
043: return false;
044: }
045:
046: public BasicCollectionPersister(Collection collection,
047: CacheConcurrencyStrategy cache, Configuration cfg,
048: SessionFactoryImplementor factory) throws MappingException,
049: CacheException {
050: super (collection, cache, cfg, factory);
051: }
052:
053: /**
054: * Generate the SQL DELETE that deletes all rows
055: */
056: protected String generateDeleteString() {
057:
058: Delete delete = new Delete().setTableName(qualifiedTableName)
059: .setPrimaryKeyColumnNames(keyColumnNames);
060:
061: if (hasWhere)
062: delete.setWhere(sqlWhereString);
063:
064: if (getFactory().getSettings().isCommentsEnabled()) {
065: delete.setComment("delete collection " + getRole());
066: }
067:
068: return delete.toStatementString();
069: }
070:
071: /**
072: * Generate the SQL INSERT that creates a new row
073: */
074: protected String generateInsertRowString() {
075:
076: Insert insert = new Insert(getDialect()).setTableName(
077: qualifiedTableName).addColumns(keyColumnNames);
078:
079: if (hasIdentifier)
080: insert.addColumn(identifierColumnName);
081:
082: if (hasIndex /*&& !indexIsFormula*/) {
083: insert.addColumns(indexColumnNames, indexColumnIsSettable);
084: }
085:
086: if (getFactory().getSettings().isCommentsEnabled()) {
087: insert.setComment("insert collection row " + getRole());
088: }
089:
090: //if ( !elementIsFormula ) {
091: insert.addColumns(elementColumnNames, elementColumnIsSettable);
092: //}
093:
094: return insert.toStatementString();
095: }
096:
097: /**
098: * Generate the SQL UPDATE that updates a row
099: */
100: protected String generateUpdateRowString() {
101:
102: Update update = new Update(getDialect())
103: .setTableName(qualifiedTableName);
104:
105: //if ( !elementIsFormula ) {
106: update.addColumns(elementColumnNames, elementColumnIsSettable);
107: //}
108:
109: if (hasIdentifier) {
110: update
111: .setPrimaryKeyColumnNames(new String[] { identifierColumnName });
112: } else if (hasIndex && !indexContainsFormula) {
113: update.setPrimaryKeyColumnNames(ArrayHelper.join(
114: keyColumnNames, indexColumnNames));
115: } else {
116: update.setPrimaryKeyColumnNames(ArrayHelper.join(
117: keyColumnNames, elementColumnNames,
118: elementColumnIsInPrimaryKey));
119: }
120:
121: if (getFactory().getSettings().isCommentsEnabled()) {
122: update.setComment("update collection row " + getRole());
123: }
124:
125: return update.toStatementString();
126: }
127:
128: /**
129: * Generate the SQL DELETE that deletes a particular row
130: */
131: protected String generateDeleteRowString() {
132:
133: Delete delete = new Delete().setTableName(qualifiedTableName);
134:
135: if (hasIdentifier) {
136: delete
137: .setPrimaryKeyColumnNames(new String[] { identifierColumnName });
138: } else if (hasIndex && !indexContainsFormula) {
139: delete.setPrimaryKeyColumnNames(ArrayHelper.join(
140: keyColumnNames, indexColumnNames));
141: } else {
142: delete.setPrimaryKeyColumnNames(ArrayHelper.join(
143: keyColumnNames, elementColumnNames,
144: elementColumnIsInPrimaryKey));
145: }
146:
147: if (getFactory().getSettings().isCommentsEnabled()) {
148: delete.setComment("delete collection row " + getRole());
149: }
150:
151: return delete.toStatementString();
152: }
153:
154: public boolean consumesEntityAlias() {
155: return false;
156: }
157:
158: public boolean consumesCollectionAlias() {
159: // return !isOneToMany();
160: return true;
161: }
162:
163: public boolean isOneToMany() {
164: return false;
165: }
166:
167: public boolean isManyToMany() {
168: return elementType.isEntityType(); //instanceof AssociationType;
169: }
170:
171: protected int doUpdateRows(Serializable id,
172: PersistentCollection collection, SessionImplementor session)
173: throws HibernateException {
174:
175: if (ArrayHelper.isAllFalse(elementColumnIsSettable))
176: return 0;
177:
178: try {
179: PreparedStatement st = null;
180: Expectation expectation = Expectations
181: .appropriateExpectation(getUpdateCheckStyle());
182: boolean callable = isUpdateCallable();
183: boolean useBatch = expectation.canBeBatched();
184: Iterator entries = collection.entries(this );
185: String sql = getSQLUpdateRowString();
186: int i = 0;
187: int count = 0;
188: while (entries.hasNext()) {
189: Object entry = entries.next();
190: if (collection.needsUpdating(entry, i, elementType)) {
191: int offset = 1;
192:
193: if (useBatch) {
194: if (st == null) {
195: if (callable) {
196: st = session.getBatcher()
197: .prepareBatchCallableStatement(
198: sql);
199: } else {
200: st = session.getBatcher()
201: .prepareBatchStatement(sql);
202: }
203: }
204: } else {
205: if (callable) {
206: st = session.getBatcher()
207: .prepareCallableStatement(sql);
208: } else {
209: st = session.getBatcher().prepareStatement(
210: sql);
211: }
212: }
213:
214: try {
215: offset += expectation.prepare(st);
216: int loc = writeElement(st, collection
217: .getElement(entry), offset, session);
218: if (hasIdentifier) {
219: writeIdentifier(st, collection
220: .getIdentifier(entry, i), loc,
221: session);
222: } else {
223: loc = writeKey(st, id, loc, session);
224: if (hasIndex && !indexContainsFormula) {
225: writeIndexToWhere(st, collection
226: .getIndex(entry, i, this ), loc,
227: session);
228: } else {
229: writeElementToWhere(st, collection
230: .getSnapshotElement(entry, i),
231: loc, session);
232: }
233: }
234:
235: if (useBatch) {
236: session.getBatcher()
237: .addToBatch(expectation);
238: } else {
239: expectation.verifyOutcome(st
240: .executeUpdate(), st, -1);
241: }
242: } catch (SQLException sqle) {
243: if (useBatch) {
244: session.getBatcher().abortBatch(sqle);
245: }
246: throw sqle;
247: } finally {
248: if (!useBatch) {
249: session.getBatcher().closeStatement(st);
250: }
251: }
252: count++;
253: }
254: i++;
255: }
256: return count;
257: } catch (SQLException sqle) {
258: throw JDBCExceptionHelper.convert(
259: getSQLExceptionConverter(), sqle,
260: "could not update collection rows: "
261: + MessageHelper.collectionInfoString(this ,
262: id, getFactory()),
263: getSQLUpdateRowString());
264: }
265: }
266:
267: public String selectFragment(Joinable rhs, String rhsAlias,
268: String lhsAlias, String entitySuffix,
269: String collectionSuffix, boolean includeCollectionColumns) {
270: // we need to determine the best way to know that two joinables
271: // represent a single many-to-many...
272: if (rhs != null && isManyToMany() && !rhs.isCollection()) {
273: AssociationType elementType = ((AssociationType) getElementType());
274: if (rhs.equals(elementType
275: .getAssociatedJoinable(getFactory()))) {
276: return manyToManySelectFragment(rhs, rhsAlias,
277: lhsAlias, collectionSuffix);
278: }
279: }
280: return includeCollectionColumns ? selectFragment(lhsAlias,
281: collectionSuffix) : "";
282: }
283:
284: private String manyToManySelectFragment(Joinable rhs,
285: String rhsAlias, String lhsAlias, String collectionSuffix) {
286: SelectFragment frag = generateSelectFragment(lhsAlias,
287: collectionSuffix);
288:
289: String[] elementColumnNames = rhs.getKeyColumnNames();
290: frag.addColumns(rhsAlias, elementColumnNames,
291: elementColumnAliases);
292: appendIndexColumns(frag, lhsAlias);
293: appendIdentifierColumns(frag, lhsAlias);
294:
295: return frag.toFragmentString().substring(2); //strip leading ','
296: }
297:
298: /**
299: * Create the <tt>CollectionLoader</tt>
300: *
301: * @see org.hibernate.loader.collection.BasicCollectionLoader
302: */
303: protected CollectionInitializer createCollectionInitializer(
304: java.util.Map enabledFilters) throws MappingException {
305: return BatchingCollectionInitializer
306: .createBatchingCollectionInitializer(this , batchSize,
307: getFactory(), enabledFilters);
308: }
309:
310: public String fromJoinFragment(String alias, boolean innerJoin,
311: boolean includeSubclasses) {
312: return "";
313: }
314:
315: public String whereJoinFragment(String alias, boolean innerJoin,
316: boolean includeSubclasses) {
317: return "";
318: }
319:
320: protected CollectionInitializer createSubselectInitializer(
321: SubselectFetch subselect, SessionImplementor session) {
322: return new SubselectCollectionLoader(this, subselect
323: .toSubselectString(getCollectionType()
324: .getLHSPropertyName()), subselect.getResult(),
325: subselect.getQueryParameters(), subselect
326: .getNamedParameterLocMap(), session
327: .getFactory(), session.getEnabledFilters());
328: }
329:
330: }
|