我有一个在表格中有大量数据的应用程序,我正在编写一个获取一小部分数据的移动应用程序。表中的数据使用ID作为关系,我正在尝试将其加载到Core Data模型中并保留关系。
但似乎没有一种简单的方法来告诉Core Data,“对于这种关系,我想要一个外键到另一个表。”相反,我有这种怪异(这是六个异步RestKit查询之一的简化版本,它们将回来填充数据库):
[manager postObject:nil path:@"api/shiftservice/get" parameters:@{@"workerIds": @[@1]} success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(@"Loaded shifts: %d", [[mappingResult array] count]);
NSManagedObjectContext *context = [AppDelegate managedObjectContext];
NSSet *positions = [context fetchObjectsForEntityName:@"NWPosition"];
NSDictionary *positionDict = [NSMutableDictionary new];
for (NWPosition *position in positions) [positionDict setValue:position forKey:position.positionId.stringValue];
NSSet *workers = [context fetchObjectsForEntityName:@"NWWorker"];
NSDictionary *workerDict = [NSMutableDictionary new];
for (NWWorker *worker in workers) [workerDict setValue:worker forKey:worker.workerId.stringValue];
NSSet *shifts = [context fetchObjectsForEntityName:@"NWShift"];
for (NWShift *shift in shifts)
{
NWPosition *position = [positionDict valueForKey:shift.positionId.stringValue];
position.shifts = [context fetchObjectsForEntityName:@"NWShift" withPredicateFormat:@"positionId = %d", position.positionId];
shift.position = position;
NSSet *tradesAsGetShift = [context fetchObjectsForEntityName:@"NWTrade" withPredicateFormat:@"getShiftId = %@", shift.shiftId];
for (NWTrade *trade in tradesAsGetShift) trade.getShift = shift;
shift.tradesAsGetShift = tradesAsGetShift;
NSSet *tradesAsGiveShift = [context fetchObjectsForEntityName:@"NWTrade" withPredicateFormat:@"giveShiftId = %@", shift.shiftId];
for (NWTrade *trade in tradesAsGiveShift) trade.giveShift = shift;
shift.tradesAsGiveShift = tradesAsGiveShift;
NWWorker *worker = [workerDict valueForKey:shift.workerId.stringValue];
worker.shifts = [context fetchObjectsForEntityName:@"NWShift" withPredicateFormat:@"workerId = %d", worker.workerId];
shift.worker = worker;
}
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Failed to load shifts with error: %@", [error localizedDescription]);
}];
我在fetchObjectsForEntityName
{{1}}使用了Matt Gallagher的单行抓取修改版本。
无论如何,这对我来说似乎很可怕,就像我错过了一些明显的东西。有没有办法告诉Core Data有关数据库样式的外键?如果没有,是否有一种简单的方法来填充它们?因为为每个实体做这么多次提取肯定不是正确的方法。如果RestKit在这里有所帮助,那就更好了。
答案 0 :(得分:0)
不,但不应该设置反向关系。
答案 1 :(得分:0)
感谢Wain和他富有洞察力的评论,我设法让RestKit以合理优雅的方式为我做这件事。这是我如何设置外键关系。我设置了每个关系的两端,这样任何一组数据都可以先进入,并且关系仍可以正确填充。
首先,我设置了管理器,告诉它使用JSON序列化:
RKManagedObjectStore *store = [AppDelegate managedObjectStore];
RKObjectManager *manager = [[RKObjectManager alloc] initWithHTTPClient:oauthClient];
[RKObjectManager setSharedManager:manager];
[RKMIMETypeSerialization registerClass:[RKNSJSONSerialization class] forMIMEType:RKMIMETypeJSON];
[manager.HTTPClient registerHTTPOperationClass:[AFJSONRequestOperation class]];
[manager registerRequestOperationClass:[AFJSONRequestOperation class]];
[manager setAcceptHeaderWithMIMEType:RKMIMETypeJSON];
[manager setRequestSerializationMIMEType:RKMIMETypeJSON];
manager.managedObjectStore = store;
接下来,我设置了连接和响应描述符:
NSManagedObjectContext *context = [AppDelegate managedObjectContext];
NSDictionary *orgRels = [[NSEntityDescription entityForName:@"NWOrg" inManagedObjectContext:context] relationshipsByName];
NSDictionary *positionRels = [[NSEntityDescription entityForName:@"NWPosition" inManagedObjectContext:context] relationshipsByName];
// ...
NSIndexSet *statusCodes = RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful);
NSArray *orgConnections =
@[[self connectionForRelation:@"positions" localKey:@"orgId" foreignKey:@"orgId" withRels:orgRels],
[self connectionForRelation:@"workers" localKey:@"orgId" foreignKey:@"orgId" withRels:orgRels]];
[manager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:
[self entityMappingForName:@"NWOrg" fromDictionary:@{@"orgId": @"orgId", @"orgName": @"orgName"} withKey:@"orgId" andConnections:orgConnections]
method:RKRequestMethodAny pathPattern:@"api/orgservice/get" keyPath:nil statusCodes:statusCodes]];
NSArray *positionConnections =
@[[self connectionForRelation:@"org" localKey:@"orgId" foreignKey:@"orgId" withRels:positionRels],
[self connectionForRelation:@"shifts" localKey:@"positionId" foreignKey:@"positionId" withRels:positionRels]];
[manager addResponseDescriptor:[RKResponseDescriptor responseDescriptorWithMapping:
[self entityMappingForName:@"NWPosition" fromDictionary:@{@"positionId": @"positionId", @"orgId": @"orgId", @"name": @"positionName"} withKey:@"positionId" andConnections:positionConnections]
method:RKRequestMethodAny pathPattern:@"api/positionservice/get" keyPath:nil statusCodes:statusCodes]];
// ...
然后,我能够做出简单的请求,而且效果很好:
[manager postObject:nil path:@"api/shiftservice/get" parameters:@{@"workerIds": @[@1]}
success:^(RKObjectRequestOperation *operation, RKMappingResult *mappingResult) {
NSLog(@"Loaded shifts: %d", [[mappingResult array] count]);
} failure:^(RKObjectRequestOperation *operation, NSError *error) {
NSLog(@"Failed to load shifts with error: %@", [error localizedDescription]);
}];
注意:这使用了一些辅助方法,我将在这里重现:
- (RKConnectionDescription *)connectionForRelation:(NSString *)relation
localKey:(NSString *)localKey foreignKey:(NSString *)foreignKey
withRels:(NSDictionary *)rels
{
return [[RKConnectionDescription alloc] initWithRelationship:rels[relation]
attributes:@{localKey: foreignKey}];
}
- (RKEntityMapping *)entityMappingForName:(NSString *)name
fromDictionary:(NSDictionary *)dict withKey:(NSString *)key
{
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:name
inManagedObjectStore:[AppDelegate managedObjectStore]];
[mapping addAttributeMappingsFromDictionary:dict];
mapping.assignsDefaultValueForMissingAttributes = YES;
mapping.assignsNilForMissingRelationships = YES;
mapping.identificationAttributes = @[key];
return mapping;
}
- (RKEntityMapping *)entityMappingForName:(NSString *)name
fromDictionary:(NSDictionary *)dict withKey:(NSString *)key
andConnections:(NSArray *)connections
{
RKEntityMapping *mapping = [self entityMappingForName:name
fromDictionary:dict withKey:key];
for (RKConnectionDescription *connection in connections)
{
[mapping addConnection:connection];
}
return mapping;
}