1 21 package oracle.toplink.essentials.mappings; 23 24 import java.util.*; 25 import oracle.toplink.essentials.exceptions.*; 26 import oracle.toplink.essentials.expressions.*; 27 import oracle.toplink.essentials.indirection.ValueHolderInterface; 28 import oracle.toplink.essentials.internal.helper.*; 29 import oracle.toplink.essentials.internal.identitymaps.*; 30 import oracle.toplink.essentials.internal.queryframework.*; 31 import oracle.toplink.essentials.internal.sessions.*; 32 import oracle.toplink.essentials.sessions.DatabaseRecord; 33 import oracle.toplink.essentials.queryframework.*; 34 import oracle.toplink.essentials.internal.sessions.AbstractRecord; 35 import oracle.toplink.essentials.internal.sessions.UnitOfWorkImpl; 36 import oracle.toplink.essentials.internal.sessions.AbstractSession; 37 import oracle.toplink.essentials.descriptors.ClassDescriptor; 38 39 49 public class OneToManyMapping extends CollectionMapping implements RelationalMapping { 50 51 52 protected transient Vector targetForeignKeyFields; 53 54 55 protected transient Vector sourceKeyFields; 56 57 58 protected transient Map targetForeignKeysToSourceKeys; 59 60 61 protected transient Map sourceKeysToTargetForeignKeys; 62 63 67 public OneToManyMapping() { 68 super(); 69 70 this.targetForeignKeysToSourceKeys = new HashMap(2); 71 this.sourceKeysToTargetForeignKeys = new HashMap(2); 72 73 this.sourceKeyFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1); 74 this.targetForeignKeyFields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(1); 75 76 this.deleteAllQuery = new DeleteAllQuery(); 77 } 78 79 82 public boolean isRelationalMapping() { 83 return true; 84 } 85 86 90 public void addTargetForeignKeyField(DatabaseField targetForeignKeyField, DatabaseField sourceKeyField) { 91 this.getTargetForeignKeyFields().addElement(targetForeignKeyField); 92 this.getSourceKeyFields().addElement(sourceKeyField); 93 } 94 95 117 public void addTargetForeignKeyFieldName(String targetForeignKeyFieldName, String sourceKeyFieldName) { 118 this.addTargetForeignKeyField(new DatabaseField(targetForeignKeyFieldName), new DatabaseField(sourceKeyFieldName)); 119 } 120 121 130 protected Expression buildDefaultSelectionCriteria() { 131 Expression selectionCriteria = null; 132 Expression builder = new ExpressionBuilder(); 133 134 for (Iterator keys = this.getTargetForeignKeysToSourceKeys().keySet().iterator(); 135 keys.hasNext();) { 136 DatabaseField targetForeignKey = (DatabaseField)keys.next(); 137 DatabaseField sourceKey = (DatabaseField)this.getTargetForeignKeysToSourceKeys().get(targetForeignKey); 138 139 Expression partialSelectionCriteria = builder.getField(targetForeignKey).equal(builder.getParameter(sourceKey)); 140 selectionCriteria = partialSelectionCriteria.and(selectionCriteria); 141 } 142 return selectionCriteria; 143 } 144 145 154 public Expression buildSelectionCriteria() { 155 Expression selectionCriteria = null; 157 Expression builder = new ExpressionBuilder(); 158 159 Enumeration sourceKeys = this.getSourceKeyFields().elements(); 160 for (Enumeration targetForeignKeys = this.getTargetForeignKeyFields().elements(); 161 targetForeignKeys.hasMoreElements();) { 162 DatabaseField targetForeignKey = (DatabaseField)targetForeignKeys.nextElement(); 163 DatabaseField sourceKey = (DatabaseField)sourceKeys.nextElement(); 164 Expression partialSelectionCriteria = builder.getField(targetForeignKey).equal(builder.getParameter(sourceKey)); 165 selectionCriteria = partialSelectionCriteria.and(selectionCriteria); 166 } 167 return selectionCriteria; 168 } 169 170 174 public Object clone() { 175 OneToManyMapping clone = (OneToManyMapping)super.clone(); 176 clone.setTargetForeignKeysToSourceKeys(new HashMap(this.getTargetForeignKeysToSourceKeys())); 177 return clone; 178 } 179 180 183 protected void deleteAll(DeleteObjectQuery query) throws DatabaseException { 184 Object referenceObjects = null; 185 if(usesIndirection()) { 186 Object attribute = getAttributeAccessor().getAttributeValueFromObject(query.getObject()); 187 if(attribute == null || !((ValueHolderInterface)attribute).isInstantiated()) { 188 referenceObjects = new Vector(0); 190 } 191 } 192 if(referenceObjects == null) { 193 referenceObjects = this.getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession()); 194 } 195 196 ((DeleteAllQuery)this.getDeleteAllQuery()).executeDeleteAll(query.getSession().getSessionForClass(this.getReferenceClass()), query.getTranslationRow(), this.getContainerPolicy().vectorFor(referenceObjects, query.getSession())); 197 } 198 199 204 protected void deleteReferenceObjectsLeftOnDatabase(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException { 205 Object objects = this.readPrivateOwnedForObject(query); 206 207 ContainerPolicy cp = this.getContainerPolicy(); 209 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) { 210 query.getSession().deleteObject(cp.next(iter, query.getSession())); 211 } 212 } 213 214 219 protected Vector extractForeignKeyFromReferenceObject(Object object, AbstractSession session) { 220 Vector foreignKey = new Vector(this.getTargetForeignKeysToSourceKeys().size()); 221 222 for (Iterator stream = this.getTargetForeignKeysToSourceKeys().entrySet().iterator(); 223 stream.hasNext();) { 224 Map.Entry entry = (Map.Entry)stream.next(); 225 DatabaseField targetField = (DatabaseField)entry.getKey(); 226 DatabaseField sourceField = (DatabaseField)entry.getValue(); 227 if (object == null) { 228 foreignKey.addElement(null); 229 } else { 230 Object value = this.getReferenceDescriptor().getObjectBuilder().extractValueFromObjectForField(object, targetField, session); 231 232 try { 234 value = session.getDatasourcePlatform().convertObject(value, getDescriptor().getObjectBuilder().getFieldClassification(sourceField)); 235 } catch (ConversionException e) { 236 throw ConversionException.couldNotBeConverted(this, getDescriptor(), e); 237 } 238 239 foreignKey.addElement(value); 240 } 241 } 242 return foreignKey; 243 } 244 245 250 protected Vector extractKeyFromRow(AbstractRecord row, AbstractSession session) { 251 Vector key = new Vector(this.getTargetForeignKeysToSourceKeys().size()); 252 253 for (Iterator stream = this.getTargetForeignKeysToSourceKeys().values().iterator(); 254 stream.hasNext();) { 255 DatabaseField field = (DatabaseField)stream.next(); 256 Object value = row.get(field); 257 258 try { 260 value = session.getDatasourcePlatform().convertObject(value, getDescriptor().getObjectBuilder().getFieldClassification(field)); 261 } catch (ConversionException e) { 262 throw ConversionException.couldNotBeConverted(this, getDescriptor(), e); 263 } 264 265 key.addElement(value); 266 } 267 return key; 268 } 269 270 275 public Vector getSourceKeyFieldNames() { 276 Vector fieldNames = new Vector(getSourceKeyFields().size()); 277 for (Enumeration fieldsEnum = getSourceKeyFields().elements(); 278 fieldsEnum.hasMoreElements();) { 279 fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName()); 280 } 281 282 return fieldNames; 283 } 284 285 289 public Vector getSourceKeyFields() { 290 return sourceKeyFields; 291 } 292 293 297 public Map getSourceKeysToTargetForeignKeys() { 298 return sourceKeysToTargetForeignKeys; 299 } 300 301 306 public Vector getTargetForeignKeyFieldNames() { 307 Vector fieldNames = new Vector(getTargetForeignKeyFields().size()); 308 for (Enumeration fieldsEnum = getTargetForeignKeyFields().elements(); 309 fieldsEnum.hasMoreElements();) { 310 fieldNames.addElement(((DatabaseField)fieldsEnum.nextElement()).getQualifiedName()); 311 } 312 313 return fieldNames; 314 } 315 316 320 public Vector getTargetForeignKeyFields() { 321 return targetForeignKeyFields; 322 } 323 324 328 public Map getTargetForeignKeysToSourceKeys() { 329 return targetForeignKeysToSourceKeys; 330 } 331 332 338 public Map getTargetForeignKeyToSourceKeys() { 339 return this.getTargetForeignKeysToSourceKeys(); 340 } 341 342 347 public boolean hasInverseConstraintDependency() { 348 return true; 349 } 350 351 355 public void initialize(AbstractSession session) throws DescriptorException { 356 super.initialize(session); 357 358 if (!this.isSourceKeySpecified()) { 359 this.setSourceKeyFields(oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(getDescriptor().getPrimaryKeyFields())); 361 } 362 this.initializeTargetForeignKeysToSourceKeys(); 363 364 if (this.shouldInitializeSelectionCriteria()) { 365 this.setSelectionCriteria(this.buildDefaultSelectionCriteria()); 366 } 367 368 this.initializeDeleteAllQuery(); 369 } 370 371 376 protected void initializeDeleteAllQuery() { 377 ((DeleteAllQuery)this.getDeleteAllQuery()).setReferenceClass(this.getReferenceClass()); 378 if (!this.hasCustomDeleteAllQuery()) { 379 if (this.getSelectionCriteria() == null) { 381 this.getDeleteAllQuery().setSelectionCriteria(this.buildDefaultSelectionCriteria()); 382 } else { 383 this.getDeleteAllQuery().setSelectionCriteria(this.getSelectionCriteria()); 384 } 385 } 386 } 387 388 391 protected void initializeTargetForeignKeysToSourceKeys() throws DescriptorException { 392 if (this.getTargetForeignKeyFields().isEmpty()) { 393 if (this.shouldInitializeSelectionCriteria()) { 394 throw DescriptorException.noTargetForeignKeysSpecified(this); 395 } else { 396 return; 398 } 399 } 400 401 if (this.getTargetForeignKeyFields().size() != this.getSourceKeyFields().size()) { 402 throw DescriptorException.targetForeignKeysSizeMismatch(this); 403 } 404 405 for (Enumeration stream = this.getTargetForeignKeyFields().elements(); 406 stream.hasMoreElements();) { 407 this.getReferenceDescriptor().buildField((DatabaseField)stream.nextElement()); 408 } 409 410 for (Enumeration keys = this.getSourceKeyFields().elements(); keys.hasMoreElements();) { 411 this.getDescriptor().buildField((DatabaseField)keys.nextElement()); 412 } 413 414 Enumeration targetForeignKeys = this.getTargetForeignKeyFields().elements(); 415 Enumeration sourceKeys = this.getSourceKeyFields().elements(); 416 while (targetForeignKeys.hasMoreElements()) { 417 Object targetForeignKey = targetForeignKeys.nextElement(); 418 Object sourcePrimaryKey = sourceKeys.nextElement(); 419 this.getTargetForeignKeysToSourceKeys().put(targetForeignKey, sourcePrimaryKey); 420 this.getSourceKeysToTargetForeignKeys().put(sourcePrimaryKey, targetForeignKey); 421 422 } 424 } 425 426 429 public boolean isOneToManyMapping() { 430 return true; 431 } 432 433 437 protected boolean isSourceKeySpecified() { 438 return !this.getSourceKeyFields().isEmpty(); 439 } 440 441 445 protected boolean mustDeleteReferenceObjectsOneByOne() { 446 ClassDescriptor referenceDescriptor = this.getReferenceDescriptor(); 447 return referenceDescriptor.hasDependencyOnParts() || referenceDescriptor.usesOptimisticLocking() || (referenceDescriptor.hasInheritance() && referenceDescriptor.getInheritancePolicy().shouldReadSubclasses()) || referenceDescriptor.hasMultipleTables(); 448 } 449 450 454 public void postInsert(WriteObjectQuery query) throws DatabaseException, OptimisticLockException { 455 if (!this.shouldObjectModifyCascadeToParts(query)) { 456 return; 457 } 458 459 if (query.shouldCascadeOnlyDependentParts()) { 461 return; 462 } 463 464 Object objects = this.getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession()); 465 466 ContainerPolicy cp = this.getContainerPolicy(); 468 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) { 469 Object object = cp.next(iter, query.getSession()); 470 if (this.isPrivateOwned()) { 471 InsertObjectQuery insertQuery = new InsertObjectQuery(); 473 insertQuery.setObject(object); 474 insertQuery.setCascadePolicy(query.getCascadePolicy()); 475 query.getSession().executeQuery(insertQuery); 476 } else { 477 if (!query.getSession().getCommitManager().isCommitInPreModify(object)) { 481 ObjectChangeSet changeSet = null; 482 UnitOfWorkChangeSet uowChangeSet = null; 483 if (query.getSession().isUnitOfWork() && (((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet() != null)) { 484 uowChangeSet = (UnitOfWorkChangeSet)((UnitOfWorkImpl)query.getSession()).getUnitOfWorkChangeSet(); 485 changeSet = (ObjectChangeSet)uowChangeSet.getObjectChangeSetForClone(object); 486 } 487 WriteObjectQuery writeQuery = new WriteObjectQuery(); 488 writeQuery.setObject(object); 489 writeQuery.setCascadePolicy(query.getCascadePolicy()); 490 query.getSession().executeQuery(writeQuery); 491 } 492 } 493 } 494 } 495 496 500 public void postUpdate(WriteObjectQuery query) throws DatabaseException, OptimisticLockException { 501 if (!this.shouldObjectModifyCascadeToParts(query)) { 502 return; 503 } 504 505 if (!this.isAttributeValueInstantiated(query.getObject())) { 507 return; 508 } 509 510 Object objectsInMemory = this.getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession()); 512 Object objectsInDB = this.readPrivateOwnedForObject(query); 513 514 this.compareObjectsAndWrite(objectsInDB, objectsInMemory, query); 515 } 516 517 521 public void preDelete(DeleteObjectQuery query) throws DatabaseException, OptimisticLockException { 522 if (!this.shouldObjectModifyCascadeToParts(query)) { 523 return; 524 } 525 526 if (this.mustDeleteReferenceObjectsOneByOne()) { 529 Object objects = this.getRealCollectionAttributeValueFromObject(query.getObject(), query.getSession()); 530 ContainerPolicy cp = this.getContainerPolicy(); 531 for (Object iter = cp.iteratorFor(objects); cp.hasNext(iter);) { 532 DeleteObjectQuery deleteQuery = new DeleteObjectQuery(); 533 deleteQuery.setObject(cp.next(iter, query.getSession())); 534 deleteQuery.setCascadePolicy(query.getCascadePolicy()); 535 query.getSession().executeQuery(deleteQuery); 536 } 537 if (!query.getSession().isUnitOfWork()) { 538 this.deleteReferenceObjectsLeftOnDatabase(query); 542 } 543 } else { 544 this.deleteAll(query); 545 } 546 } 547 548 563 public void setDeleteAllSQLString(String sqlString) { 564 DeleteAllQuery query = new DeleteAllQuery(); 565 query.setSQLString(sqlString); 566 setCustomDeleteAllQuery(query); 567 } 568 569 574 public void setSourceKeyFieldNames(Vector fieldNames) { 575 Vector fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size()); 576 for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) { 577 fields.addElement(new DatabaseField((String )fieldNamesEnum.nextElement())); 578 } 579 580 setSourceKeyFields(fields); 581 } 582 583 587 public void setSourceKeyFields(Vector sourceKeyFields) { 588 this.sourceKeyFields = sourceKeyFields; 589 } 590 591 614 public void setTargetForeignKeyFieldName(String targetForeignKeyFieldName) { 615 this.getTargetForeignKeyFields().addElement(new DatabaseField(targetForeignKeyFieldName)); 616 } 617 618 627 public void setTargetForeignKeyFieldNames(String [] targetForeignKeyFieldNames, String [] sourceKeyFieldNames) { 628 if (targetForeignKeyFieldNames.length != sourceKeyFieldNames.length) { 629 throw DescriptorException.targetForeignKeysSizeMismatch(this); 630 } 631 for (int i = 0; i < targetForeignKeyFieldNames.length; i++) { 632 this.addTargetForeignKeyFieldName(targetForeignKeyFieldNames[i], sourceKeyFieldNames[i]); 633 } 634 } 635 636 641 public void setTargetForeignKeyFieldNames(Vector fieldNames) { 642 Vector fields = oracle.toplink.essentials.internal.helper.NonSynchronizedVector.newInstance(fieldNames.size()); 643 for (Enumeration fieldNamesEnum = fieldNames.elements(); fieldNamesEnum.hasMoreElements();) { 644 fields.addElement(new DatabaseField((String )fieldNamesEnum.nextElement())); 645 } 646 647 setTargetForeignKeyFields(fields); 648 } 649 650 654 public void setTargetForeignKeyFields(Vector targetForeignKeyFields) { 655 this.targetForeignKeyFields = targetForeignKeyFields; 656 } 657 658 662 protected void setTargetForeignKeysToSourceKeys(Map targetForeignKeysToSourceKeys) { 663 this.targetForeignKeysToSourceKeys = targetForeignKeysToSourceKeys; 664 } 665 666 671 protected boolean shouldObjectModifyCascadeToParts(ObjectLevelModifyQuery query) { 672 if (this.isReadOnly()) { 673 return false; 674 } 675 676 if (this.isPrivateOwned()) { 677 return true; 678 } 679 680 return query.shouldCascadeAllParts(); 681 } 682 683 687 public boolean isCascadedLockingSupported() { 688 return true; 689 } 690 691 695 public boolean isJoiningSupported() { 696 return true; 697 } 698 699 703 public boolean verifyDelete(Object object, AbstractSession session) throws DatabaseException { 704 if (this.isPrivateOwned()) { 705 Object objects = this.getRealCollectionAttributeValueFromObject(object, session); 706 707 ContainerPolicy containerPolicy = getContainerPolicy(); 708 for (Object iter = containerPolicy.iteratorFor(objects); containerPolicy.hasNext(iter);) { 709 if (!session.verifyDelete(containerPolicy.next(iter, session))) { 710 return false; 711 } 712 } 713 } 714 return true; 715 } 716 } 717 | Popular Tags |