Annotation of Examples/EnterpriseObjects/MasteringDetails/EOFExtensions.subproj/KeyGenerator.m, revision 1.1.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.