|
|
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
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.