Annotation of Examples/EnterpriseObjects/MasteringDetails/EOFExtensions.subproj/SavvyControllerDelegate.m, revision 1.1

1.1     ! root        1: /* ModelSavyController.m created by cfeder on Tue 01-Nov-1994 */
        !             2: 
        !             3: /*
        !             4:    Interesting master-detail relationships:
        !             5:    M     Detail   Insert rule              Delete                 Types
        !             6:    PK -> PK       D->PK := M->PK           delete D               to-one
        !             7:    FK -> PK       M->FK := D->PK           M->FK=NULL             to-one
        !             8:    PK -> FK       D->FK := M->PK           Delete D               to-many
        !             9:    Many to many   create link obj          Delete link            to-many
        !            10: */
        !            11: #import "SavvyControllerDelegate.h"
        !            12: #import "RelationshipKeySetter.h"
        !            13: #import "ResetRelationships.h"
        !            14: #import "KeyGenerator.h"
        !            15: #import "ValueForKey.h"
        !            16: 
        !            17: 
        !            18: @interface EODetailDatabaseDataSource (databaseChannel)
        !            19: - (EODatabaseChannel *)databaseChannel;
        !            20: @end
        !            21: 
        !            22: @implementation EODetailDatabaseDataSource (databaseChannel)
        !            23: - (EODatabaseChannel *)databaseChannel
        !            24: {
        !            25:     return [[self masterDataSource] databaseChannel];
        !            26: }
        !            27: @end
        !            28: 
        !            29: 
        !            30: 
        !            31: @implementation SavvyControllerDelegate
        !            32: 
        !            33: - (EORelationship *)detailRelationshipForController:controller;
        !            34: {
        !            35:     // Look up
        !            36:     id dataSource = [controller dataSource];
        !            37:     if ([dataSource respondsToSelector:@selector(masterObject)]) {
        !            38:         EOEntity *entity = [dataSource entity];
        !            39:         id masterObject = [dataSource masterObject];
        !            40:         EOEntity *masterEntity = [[entity model] entityForObject:masterObject];
        !            41:         return [masterEntity relationshipNamed:[dataSource detailKey]];        
        !            42:     }
        !            43:     return nil;
        !            44: }
        !            45: 
        !            46: - (void)updateDetailObjectsForController:(EOController *)controller
        !            47: {
        !            48:     EORelationship *relationship = [self detailRelationshipForController:controller];
        !            49:     if (relationship) {
        !            50:         // if this is a detail controller, then we may have to update
        !            51:         // the relationship property of the master EO, since we
        !            52:         // may have supressed insert and delete operations bound
        !            53:         // for the detailDataSource
        !            54:         id masterObject = [(id)[controller dataSource] masterObject];
        !            55:         NSArray *objects = [controller allObjects];
        !            56:         if ([relationship isToMany]) {
        !            57:             objects = [[[NSArray alloc] initWithArray:objects] autorelease];
        !            58:         } else {
        !            59:             objects = [objects count] ? [objects objectAtIndex:0] : [EONull null];
        !            60:         }
        !            61:         [masterObject takeValue:objects forKey:[relationship name]];
        !            62:     }
        !            63: }
        !            64: 
        !            65: 
        !            66: 
        !            67: // EOController delegation methods
        !            68: 
        !            69: - (BOOL)controller:(EOController *)controller willInsertObject:object atIndex: (unsigned)newIndex;
        !            70: {
        !            71:     // Handles primary key assignment for newly inserted objects.
        !            72:     EOEntity *entity = [(id)[controller dataSource] entity];
        !            73:     [object assignPrimaryKeyIfNotAlreadyPresentForEntity:entity];
        !            74: 
        !            75:     return YES;
        !            76: }
        !            77: 
        !            78: // Handles insertions into a detail controller.  The tricky part here is
        !            79: // that if we assign a new department in the detail controller for
        !            80: // an employee, we don't want to actually add the department to the
        !            81: // database (it's already there).  Instead, we want to update the foreign
        !            82: // key in the master object to point at the new department.
        !            83: // Similarly if we insert a project in the toProjects (many-to-many) detail
        !            84: // controller, we don't want to insert the project, but rather a "link"
        !            85: // object in the intermediate table emp_projects that joins employee and
        !            86: // project.
        !            87: - (EODataSourceOperationDelegateResponse)controller:(EOController *)controller
        !            88:     willInsertObject:object
        !            89:     inDataSource:dataSource;
        !            90: {
        !            91:     EODataSourceOperationDelegateResponse response = EOPerformDataSourceOperation;
        !            92:     EORelationship *relationship = [self detailRelationshipForController:controller];
        !            93: 
        !            94:     // This stuff only works if our dataSource is an EODetailDatabaseDataSource.
        !            95:     // Otherwise we just pass the operation through
        !            96:     if (relationship) {
        !            97:         id masterObject = [dataSource masterObject];
        !            98:         id modifiedObject;
        !            99:         EODatabaseDataSource *masterDataSource =  [dataSource masterDataSource];
        !           100: 
        !           101:         // Invoke the magic of the ModelRelExtensions to figure out what to
        !           102:         // do for this relationship
        !           103:         modifiedObject = [relationship updateKeysForSourceObject:masterObject destinationObject:object];
        !           104: 
        !           105:         if (modifiedObject == object) {
        !           106:             modifiedObject = nil;
        !           107:         } else if (modifiedObject == masterObject) {
        !           108:             // we need to update this one as well
        !           109:             NSLog(@"Updating master object '%@'", masterObject);
        !           110:             if (![masterDataSource updateObject:masterObject])
        !           111:                 response = EORollbackDataSourceOperation;  // put up error?
        !           112:         } else {
        !           113:             // link object that we need to insert
        !           114:             NSLog(@"Inserting link object '%@'", modifiedObject);
        !           115:             if (![masterDataSource insertObject:modifiedObject])
        !           116:                 response = EORollbackDataSourceOperation;  // put up error?
        !           117:         }
        !           118: 
        !           119:         if (modifiedObject) {
        !           120:             // do we really need to insert this object?  Or did the insert just indicate
        !           121:             // a reference to an existing object?
        !           122:             EODatabaseContext *context = [[dataSource databaseChannel] databaseContext];
        !           123:             if ([context snapshotForObject:object])
        !           124:                 response = EODiscardDataSourceOperation;
        !           125:         }
        !           126:     }    
        !           127:     if (response == EOPerformDataSourceOperation)
        !           128:         NSLog(@"Allowing insert of object '%@'", object);
        !           129:     else {
        !           130:         NSLog(@"Suppressing insert of object: '%@'", object);
        !           131:     }
        !           132:     return response;
        !           133: }
        !           134: 
        !           135: - (EODataSourceOperationDelegateResponse)controller:(EOController *)controller
        !           136:     willDeleteObject:object
        !           137:     inDataSource:dataSource;
        !           138: {
        !           139:     /*Deletion of detail record may dictate one of the following...
        !           140:        M     Detail   Insert rule              Delete                 Types
        !           141:        PK -> PK       D->PK := M->PK           delete D               to-one
        !           142:        FK -> PK       M->FK := D->PK           M->FK=NULL             to-one
        !           143:        PK -> FK       D->FK := M->PK           Delete D               to-many
        !           144:        Many to many   create link obj          Delete link            to-many
        !           145:     */
        !           146:     EODataSourceOperationDelegateResponse response = EOPerformDataSourceOperation;
        !           147:     EORelationship *relationship = [self detailRelationshipForController:controller];
        !           148: 
        !           149:     // This stuff only works if our dataSource is an EODetailDatabaseDataSource.
        !           150:     // Otherwise we just pass the operation through
        !           151:     if (relationship) {
        !           152:         EOEntity *entity = [relationship destinationEntity];
        !           153:         id masterObject = [dataSource masterObject];
        !           154:         id modifiedObject;
        !           155: 
        !           156:         // Invoke the magic of the ModelRelExtensions to figure out what to
        !           157:         // do for this relationship
        !           158:         modifiedObject = [relationship updateKeysForDeleteOfDestinationObject:object fromSourceObject:masterObject];
        !           159: 
        !           160:         if (modifiedObject == object) {
        !           161:             // just go ahead and delete this one
        !           162:         } else if (modifiedObject == masterObject) {
        !           163:             // we need to update the master to reflect the delete
        !           164:             // and leave this object alone
        !           165:             response = EODiscardDataSourceOperation;
        !           166:             NSLog(@"Updating master object '%@'", masterObject);
        !           167:             if (![dataSource updateObject:masterObject])
        !           168:                 response = EORollbackDataSourceOperation;  // put up error?
        !           169:         } else {
        !           170:             // we need to delete the link object
        !           171:             // and leave this object alone
        !           172:             EODatabaseContext *context = [[dataSource databaseChannel] databaseContext];
        !           173:             EODatabase *database = [context database];
        !           174:             EOEntity *linkEntity = [[entity model] entityForObject:modifiedObject];
        !           175:             NSDictionary *pkDict;
        !           176:             id registeredObject;
        !           177: 
        !           178:             response = EODiscardDataSourceOperation; // leave destination object alone
        !           179: 
        !           180:             // to delete the object we need to make sure that it's in the uniquing
        !           181:             // tables.  Check if it's already there, and if not, record this one
        !           182:             pkDict = [modifiedObject valuesForKeys:[linkEntity primaryKeyAttributeNames]];
        !           183:             registeredObject = [context objectForPrimaryKey:pkDict entity:linkEntity];
        !           184:             if (!registeredObject) {
        !           185:                 [database recordObject:modifiedObject primaryKey:pkDict
        !           186:                              snapshot:pkDict];
        !           187:                 registeredObject = modifiedObject;
        !           188:             }
        !           189:             NSLog(@"Deleting link object '%@'", registeredObject);
        !           190:             if (![[dataSource masterDataSource] deleteObject:registeredObject])
        !           191:                 response = EORollbackDataSourceOperation;  // put up error?
        !           192:         }
        !           193:     }
        !           194:     if (response == EOPerformDataSourceOperation)
        !           195:         NSLog(@"Allowing delete of object '%@'", object);
        !           196:     else {
        !           197:         NSLog(@"Suppressing delete of object: '%@'", object);
        !           198:     }
        !           199:     return response;
        !           200: }
        !           201: 
        !           202: - (void)controllerDidSaveToDataSource:(EOController *)controller
        !           203: {
        !           204:     [self updateDetailObjectsForController:controller];
        !           205: }
        !           206: 
        !           207: @end
        !           208: 
        !           209: 
        !           210: // This is probably evil.
        !           211: // This code checks modifications to foreign key properties in an EO, and
        !           212: // reassigns any corresponding relationship pointers using methods in
        !           213: // ResetRelationships.h.
        !           214: //
        !           215: // THIS CODE IS NOT ACTUALLY USED IN THE EXAMPLE PROGRAM, but is here as
        !           216: // an illustration.
        !           217: @implementation SavvyControllerDelegate (ResetRelationshipsForChangedKeyProps)
        !           218: static NSArray *changedKeys = nil;
        !           219: 
        !           220: - (NSDictionary *)controller:(EOController *)controller willSaveEdits: (NSDictionary *)edits toObject:object
        !           221: {
        !           222:     // update any related relationship properties (in case we update foreign keys)
        !           223:     changedKeys = [edits allKeys];
        !           224:     return edits;
        !           225: }
        !           226: 
        !           227: - (void)controller:(EOController *)controller didSaveToObject:object
        !           228: {
        !           229:     EODatabaseDataSource *ds = (EODatabaseDataSource *)[controller dataSource];
        !           230:     EOEntity *entity = [ds entity];
        !           231: 
        !           232:     // update relationships for key changes
        !           233:     [[ds databaseChannel] updateRelationshipsInObject:object forModifiedAttributes:[entity attributesNamed:changedKeys]];
        !           234: 
        !           235:     // update keys for relationship changes
        !           236:     {
        !           237:         int i, count = [changedKeys count];
        !           238:         for(i=0; i<count; i++) {
        !           239:             NSString *key = [changedKeys objectAtIndex:i];
        !           240:             EORelationship *relationship = [entity relationshipNamed:key];
        !           241:             if (relationship) {
        !           242:                 [relationship updateKeysForSourceObject:object
        !           243:                                       destinationObject:[(NSObject *)object valueForKey:key]];
        !           244:             }
        !           245:         }
        !           246:     }
        !           247: }
        !           248: @end

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.