从现有数据库ID关系加载核心数据关系

时间:2014-01-30 23:27:16

标签: core-data restkit

我有一个在表格中有大量数据的应用程序,我正在编写一个获取一小部分数据的移动应用程序。表中的数据使用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在这里有所帮助,那就更好了。

2 个答案:

答案 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;
}