2012-10-24 41 views
4

我試圖通過RestKit將用戶和組映射到CoreData對象,維護兩者之間的關係。通過ID數組映射關係在RestKit中不起作用

的JSON的用戶是一樣的東西

{"users": 
    [{"fullname": "John Doe", "_id": "1"} 
    ... 
    ] 
} 

和JSON的羣體是一樣的東西

{"groups": 
    [{"name": "John's group", "_id": "a", 
    "members": ["1", "2"] 
    ... 
    ] 
} 

我也有相應的核心數據對象,UserGroup,有一個組與用戶之間的多對一關係映射。 Group中的關係屬性被稱爲members,單獨的NSArray被稱爲memberIDs包含所有成員用戶的字符串ID數組。

我想在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顯然會錯代碼,它似乎與我在上面的代碼中創建的虛假用戶映射有關(它是空的,因爲沒有要在ID數組中映射的東西)。

我試過的替代品,例如,當我添加了關鍵路徑映射:

[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正試圖在ID字符串本身的memberIDs陣列中映射到User對象,它們不作任何意義。我見過的例子,其中的關係陣列是連鍵的字典(例如稱爲id)與參考ID到其他對象的列表,例如:

{"groups": 
    [{"name": "John's group", "_id": "a", 
    "members": [ 
     {"_id": "1"}, 
     {"_id": "2"} 
    ] 
    ... 
    ] 
} 

但我不想改變我的JSON (除此之外,我希望RestKit足夠靈活以支持其他方式)。

有沒有人知道在RestKit中做這種關係映射的正確方法是什麼?

更新

我最後修改REST接口發送包含用戶對象ID(就像上面的最後一個例子)的詞典列表,並得到了工作。仍然不完全滿意的設置,但代碼現在看起來像

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) {}]; 

以防萬一這可以幫助其他人在類似的情況。我採取的方法可能仍然存在一些問題,但如此之好(甚至可以處理亂序加載,這很好) - 如果對我的原始問題有答案,仍然樂於聽到任何人的聲音。

回答

2

找到了一種方法來完成這項工作,也意識到我的問題中更新的方法只能用於嵌套對象,而不是引用對象。此線程讓我在正確的軌道上:https://groups.google.com/forum/#!msg/restkit/swB1Akv2lTE/mnP2OMSqElwJ(值得一讀,如果你正在處理中RestKit關係)

假設組JSON看起來還是像原來的JSON:

{"groups": 
    [{"name": "John's group", "_id": "a", 
    "members": ["1", "2"] 
    ... 
    ] 
} 

而且假設用戶映射到的keyPath users(即在類似[objectManager.mappingProvider setMapping:userMapping forKeyPath:@"users"];)正確的方式映射的關係是這樣的:

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"]; 

[groupMapping mapKeyPath:@"users" toRelationship:@"members" withMapping:[[RKObjectManager sharedManager].mappingProvider objectMappingForKeyPath:@"users"] serialize:NO]; 
[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) {}]; 

當我試過這種方法早些時候,該conf下的東西用於我的是這條線

[groupMapping mapKeyPath:@"users" toRelationship:@"members" withMapping:[[RKObjectManager sharedManager].mappingProvider objectMappingForKeyPath:@"users"] serialize:NO]; 

其中第一鍵路徑指的是用於被引用的對象的關鍵路徑映射(users在這種情況下),沒有被映射到的group對象內的關係的關鍵路徑(在這種情況下將會是members)。

有了這個變化,所有的關係都按預期工作,我很高興。

+0

嘿!我正在嘗試做同樣的事情,但我想知道,CoreData中的memberIDS類型是什麼?我會盡快嘗試!謝謝! – abisson

+0

@abisson檢查Blake Watters的這個答案:https://groups.google.com/d/msg/restkit/9MG0CPi1aS0/olQGaSiJQjAJ – vitaminwater