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

1.1     ! root        1: /* KeyGenerator.m created by cfeder on Wed 26-Oct-1994 */
        !             2: 
        !             3: #import "KeyGenerator.h"
        !             4: #import "ValueForKey.h"
        !             5: 
        !             6: // Default implementation for all EOs to generate their own primary keys
        !             7: @implementation NSObject (assignPrimaryKey)
        !             8: - (void)assignPrimaryKeyForEntity:(EOEntity *)entity
        !             9: {
        !            10:     NSString *primaryKeyName = [[entity primaryKeyAttributeNames] objectAtIndex:0];
        !            11:     NSNumber *value = [NSNumber numberWithUnsignedInt:[KeyGenerator nexKeyForEntity:entity]];
        !            12:     NSDictionary *pkDict = [NSDictionary dictionaryWithObjects:&value forKeys:&primaryKeyName count:1];
        !            13:     [self takeValuesFromDictionary:pkDict];
        !            14: }
        !            15: 
        !            16: - (void)assignPrimaryKeyIfNotAlreadyPresentForEntity:(EOEntity *)entity
        !            17: {
        !            18:     // Figure out whether we already have a key assigned
        !            19:     BOOL hasKey = NO;
        !            20:     NSEnumerator *keys = [[entity primaryKeyAttributeNames] objectEnumerator];
        !            21:     NSString *key;
        !            22:     while (key = [keys nextObject]) {
        !            23:         id value = [self valueForKey:key];
        !            24:         if (value && (value != [EONull null]) && (![value isKindOfClass:[NSNumber class]] || ([value intValue]!=0))){
        !            25:             hasKey = YES;
        !            26:             break;
        !            27:         }
        !            28:     }
        !            29: 
        !            30:     // if we don't already have a primary key, then assign ourselves one
        !            31:     // get our current primary key values
        !            32:     if (!hasKey) {
        !            33:         [self assignPrimaryKeyForEntity:entity];
        !            34:     }
        !            35: }
        !            36: @end
        !            37: 
        !            38: // Assumptions:
        !            39: // Model contains:
        !            40: // - login information
        !            41: // - UniqueKey entity with attributes entity_name, and max_key
        !            42: 
        !            43: 
        !            44: @implementation KeyGenerator
        !            45: #define RESERVE_SET_SIZE 5
        !            46: 
        !            47: 
        !            48: - initWithEntity:(EOEntity *)anEntity dataSource:(EODatabaseDataSource *)aDataSource
        !            49: {
        !            50:     [super init];
        !            51:     entity = [anEntity retain];
        !            52:     dataSource = [aDataSource retain];
        !            53:     lastGranted = lastReserved = 0;
        !            54:     return self;
        !            55: }
        !            56: 
        !            57: - (unsigned)nextKey
        !            58: {
        !            59:     if (lastGranted >= lastReserved) {
        !            60:         // Go out to database and reserve a block of keys
        !            61:         EOQualifier    *tableNameQualifier;
        !            62:         EODatabaseChannel *channel = [dataSource databaseChannel];
        !            63:         EODatabaseContext *context = [channel databaseContext];
        !            64:         NSString *externalName = [entity externalName];
        !            65:         EOEntity *uniqueKeyEntity = [dataSource entity];
        !            66: 
        !            67:         if (!uniqueKeyEntity)
        !            68:             [NSException raise:NSInternalInconsistencyException format:@"%s: model does not contain UniqueKey entity '%@'", sel_getName(_cmd), [entity name]];
        !            69: 
        !            70:         if (![channel isOpen])
        !            71:             [channel openChannel];
        !            72:         [context beginTransaction];
        !            73: 
        !            74:         // This is the first time for this entity.  We need to get the current setting.
        !            75:         if (!currentMaxRecord) {
        !            76:             // Construct the qualifier for our name
        !            77:             tableNameQualifier = [[[EOQualifier alloc] initWithEntity:uniqueKeyEntity
        !            78:                                    qualifierFormat:@"%A= '%@'", @"entity_name", externalName] autorelease];
        !            79:             [channel selectObjectsDescribedByQualifier:tableNameQualifier fetchOrder:nil];
        !            80:             currentMaxRecord = [[channel fetchWithZone:[self zone]] retain];
        !            81:             [channel cancelFetch];
        !            82:         }
        !            83: 
        !            84:         if (currentMaxRecord) {
        !            85:             // attempt to update the max_key value
        !            86:             for(;;) {
        !            87:                 lastGranted = [[currentMaxRecord objectForKey:@"max_key"] unsignedIntValue];
        !            88:                 lastReserved = lastGranted + RESERVE_SET_SIZE;
        !            89:                 [currentMaxRecord setObject:[NSNumber numberWithUnsignedInt:lastReserved] forKey:@"max_key"];
        !            90: 
        !            91:                 if ([channel updateObject:currentMaxRecord] && [context commitTransaction])
        !            92:                     break;  // success!!
        !            93: 
        !            94:                 // Update failed.  Setup for another pass
        !            95:                 [context rollbackTransaction];
        !            96:                 [context beginTransaction];
        !            97:                 [channel refetchObject:currentMaxRecord];
        !            98:             }
        !            99:         } else {
        !           100:             // we have to insert a record for this entity
        !           101:             currentMaxRecord = [[EOGenericRecord alloc] initWithPrimaryKey:nil entity:uniqueKeyEntity];  // retained
        !           102:             [currentMaxRecord setObject:externalName forKey:@"entity_name"];
        !           103:             lastReserved = RESERVE_SET_SIZE;
        !           104:             lastGranted = 0;
        !           105:             [currentMaxRecord setObject:[NSNumber numberWithUnsignedInt:lastReserved] forKey:@"max_key"];
        !           106:             NSLog(@"Entity '%@' not in UniqueKey table.  Adding record: %@", [entity name], currentMaxRecord);
        !           107:             if (![channel insertObject:currentMaxRecord])
        !           108:                 [NSException raise:NSInternalInconsistencyException format:@"Failed to insert UniqueKey object for entity: %@", [entity name]];
        !           109:             [context commitTransaction];
        !           110:         }
        !           111:     }
        !           112: 
        !           113:     lastGranted++;        
        !           114:     return lastGranted;
        !           115: }
        !           116: 
        !           117: - (void)dealloc
        !           118: {
        !           119:     [entity release];
        !           120:     [dataSource release];
        !           121:     [super dealloc];
        !           122: }
        !           123: 
        !           124: 
        !           125: //
        !           126: // Class methods to automatically cache instances
        !           127: //
        !           128: static NSMutableDictionary *entityNameToGenerator;
        !           129: 
        !           130: + (EODatabaseDataSource *)dataSourceForModel:(EOModel *)model
        !           131: {
        !           132:     // use the datasource rendevous mechanism to do our caching for us
        !           133:     return [[EODatabaseDataSource alloc] initWithModelName:[model name]
        !           134:                                                 entityName:@"unique_key"
        !           135:                                               databaseName:nil
        !           136:                                                contextName:@"_UniqueKey"
        !           137:                                                channelName:nil];
        !           138: }
        !           139: 
        !           140: + keyGeneratorForEntity:(EOEntity *)anEntity
        !           141: {
        !           142:     KeyGenerator *kg = [entityNameToGenerator objectForKey:[anEntity name]];
        !           143:     if (!kg) {
        !           144:         EODatabaseDataSource *ds = [self dataSourceForModel:[anEntity model]];
        !           145:         if (!ds)
        !           146:             [NSException raise:NSInternalInconsistencyException format:@"%s: unable to allocation UniqueKey data source for entity '%@'", sel_getName(_cmd), [anEntity name]];
        !           147:         kg = [[KeyGenerator alloc] initWithEntity:anEntity dataSource:ds];
        !           148: 
        !           149:         if (kg) {
        !           150:             if (!entityNameToGenerator)
        !           151:                 entityNameToGenerator = [NSMutableDictionary new];
        !           152:             [entityNameToGenerator setObject:kg forKey:[anEntity name]];
        !           153:         }
        !           154:     }
        !           155:     return kg;
        !           156: }
        !           157: 
        !           158: + (unsigned)nexKeyForEntity:(EOEntity *)anEntity
        !           159: {
        !           160:     KeyGenerator *kg = [self keyGeneratorForEntity:anEntity];
        !           161:     if (!kg)
        !           162:         [NSException raise:NSInternalInconsistencyException format:@"%s: unable to create KeyGenerator for entity '%@'", sel_getName(_cmd), [anEntity name]];
        !           163:     return [kg nextKey]; 
        !           164: }
        !           165: 
        !           166: @end

unix.superglobalmegacorp.com

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