Отображение отношений в RestKit через массив идентификаторов не работает
Я пытаюсь сопоставить пользователей и группы с объектами CoreData через RestKit, поддерживая отношения между ними.
JSON для пользователей это что-то вроде
{"users":
[{"fullname": "John Doe", "_id": "1"}
...
]
}
и JSON для групп это что-то вроде
{"groups":
[{"name": "John's group", "_id": "a",
"members": ["1", "2"]
...
]
}
У меня также есть соответствующие объекты Core Data,User
а такжеGroup
с сопоставлением отношений один-ко-многим между группами и пользователями. Свойство отношения вGroup
называетсяmembers
и отдельныйNSArray
называетсяmemberIDs
содержит массив идентификаторов строк всех пользователей.
Что я хочу сделать в RestKit - это загрузить эти объекты и отобразить для меня отношения. Код для загрузки пользователей - простой стандартный материал, а код для загрузки групп - что-то вроде
RKObjectManager* objectManager = [RKObjectManager sharedManager];
RKManagedObjectMapping* groupMapping = [RKManagedObjectMapping mappingForClass:[Group class] inManagedObjectStore:objectManager.objectStore];
groupMapping.primaryKeyAttribute = @"identifier";
[groupMapping mapKeyPath:@"_id" toAttribute:@"identifier"];
[groupMapping mapKeyPath:@"name" toAttribute:@"name"];
[groupMapping mapKeyPath:@"members" toAttribute:@"memberIDs"];
[objectManager.mappingProvider setMapping:groupMapping forKeyPath:@"groups"];
// Create an empty user mapping to handle the relationship mapping
RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[User class] inManagedObjectStore:objectManager.objectStore];
[groupMapping hasMany:@"members" withMapping:userMapping];
[groupMapping connectRelationship:@"members" withObjectForPrimaryKeyAttribute:@"memberIDs"];
RKObjectRouter* router = objectManager.router;
[router routeClass:[Group class] toResourcePath:@"/rest/groups/:identifier"];
[router routeClass:[Group class] toResourcePath:@"/rest/groups/" forMethod:RKRequestMethodPOST];
// Assume url is properly defined to point to the right path...
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:url usingBlock:^(RKObjectLoader *loader) {}];
Когда я запускаю этот код, я получаю следующее предупреждение несколько раз (кажется, примерно в два раза за отношения):
2012-10-24 08:55:10.170 Test[35023:18503] W restkit.core_data.cache:RKEntityByAttributeCache.m:205 Unable to add object with nil value for attribute 'identifier': <User: 0x86f7fc0> (entity: User; id: 0x8652400 <x-coredata:///User/t01A9EDBD-A523-4806-AFC2-9B06873D764E531> ; data: {
fullname = nil;
identifier = nil;
})
Странно то, что отношения устанавливаются должным образом (даже если посмотреть на базу данных sqlite, и там все выглядит хорошо), но я не доволен тем, что что-то явно идет не так в коде RestKit, и, похоже, это как-то связано с фиктивное отображение пользователя, которое я создаю в приведенном выше коде (оно пустое, поскольку в массиве идентификаторов нечего сопоставлять).
Я пробовал альтернативы, например, когда я добавляю отображение пути ключа:
[userMapping mapKeyPath:@"" toAttribute:@"identifier"];
Жалуется, очевидно, потому что ключевой путь пуст
2012-10-24 09:24:11.735 Test[35399:14003] !! Uncaught exception !!
[<__NSCFString 0xa57f460> valueForUndefinedKey:]: this class is not key value coding-compliant for the key .
И если я попытаюсь использовать реальныйUser
отображение
[groupMapping hasMany:@"members" withMapping:[[RKObjectManager sharedManager].mappingProvider objectMappingForKeyPath:@"users"]];
Я получаю следующую ошибку
2012-10-24 09:52:49.973 Test[35799:18403] !! Uncaught exception !!
[<__NSCFString 0xa56e9a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _id.
2012-10-24 09:52:49.973 Test[35799:18403] *** Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[<__NSCFString 0xa56e9a0> valueForUndefinedKey:]: this class is not key value coding-compliant for the key _id.'
Похоже, RestKit пытается сопоставить сами строки идентификатора в массиве memberIDsUser
объекты, которые не имеют никакого смысла. Я видел примеры, где массив отношений представляет собой список словарей с ключами (например, называетсяid
) со ссылкой на другой объект, например:
{"groups":
[{"name": "John's group", "_id": "a",
"members": [
{"_id": "1"},
{"_id": "2"}
]
...
]
}
Но я не хочу менять свой JSON таким образом (кроме того, я надеюсь, что RestKit достаточно гибок для поддержки другого способа).
Кто-нибудь знает, каков правильный способ создания такого рода отношений в RestKit?
Обновить
В итоге я изменил интерфейс REST для отправки списка словарей, содержащих идентификаторы объектов пользователя (как в последнем примере выше), и заставил его работать. Все еще не совсем доволен настройкой, но код теперь выглядит так
RKObjectManager* objectManager = [RKObjectManager sharedManager];
RKManagedObjectMapping* groupMapping = [RKManagedObjectMapping mappingForClass:[Group class] inManagedObjectStore:objectManager.objectStore];
groupMapping.primaryKeyAttribute = @"identifier";
[groupMapping mapKeyPath:@"_id" toAttribute:@"identifier"];
[groupMapping mapKeyPath:@"name" toAttribute:@"name"];
[groupMapping mapKeyPath:@"members._id" toAttribute:@"memberIDs"];
[objectManager.mappingProvider setMapping:groupMapping forKeyPath:@"groups"];
// Create an empty user mapping to handle the relationship mapping
RKManagedObjectMapping* userMapping = [RKManagedObjectMapping mappingForClass:[User class] inManagedObjectStore:objectManager.objectStore];
userMapping.primaryKeyAttribute = @"identifier";
[userMapping mapKeyPath:@"_id" toAttribute:@"identifier"];
[groupMapping hasMany:@"members" withMapping:userMapping];
[groupMapping connectRelationship:@"members" withObjectForPrimaryKeyAttribute:@"memberIDs"];
RKObjectRouter* router = objectManager.router;
[router routeClass:[Group class] toResourcePath:@"/rest/groups/:identifier"];
[router routeClass:[Group class] toResourcePath:@"/rest/groups/" forMethod:RKRequestMethodPOST];
// Assume url is properly defined to point to the right path...
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:url usingBlock:^(RKObjectLoader *loader) {}];
На всякий случай это поможет кому-то еще в подобной ситуации. Могут все еще быть некоторые проблемы с подходом, который я выбрал, но пока все хорошо (он даже обрабатывает загрузку вне порядка, что приятно) - все равно хотел бы услышать от кого-нибудь, если есть ответ на мой оригинальный вопрос.