通过ID数组在RestKit中映射关系

通过ID数组在RestKit中映射关系

本文介绍了通过ID数组在RestKit中映射关系不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试通过RestKit将用户和组映射到CoreData对象,维护两者之间的关系。

I'm trying to map users and groups to CoreData objects through RestKit, maintaining the relationship between the two.

用户的JSON类似于

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

和JSON for这些群组类似于

and the JSON for the groups is something like

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

我还有相应的核心数据对象,用户,在组和用户之间建立一对多的关系映射。 中的关系属性称为成员和单独的 NSArray 名为 memberIDs 保存所有成员用户的字符串ID数组。

I also have corresponding Core Data objects, User and Group, with a one-to-many relationship mapping between groups and users. The relationship property in Group is called members and a separate NSArray called memberIDs holds the array of string IDs of all member users.

我想在RestKit中完成的是加载这些对象并为我映射关系。加载用户的代码是直接的标准内容,加载组的代码类似于

What I want to accomplish in RestKit is to load these objects and have the relationship mapped for me. The code for loading the users is straight forward standard stuff, and the code for loading the groups is something like

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

当我运行此代码时,我会多次吐出以下警告(似乎是两次左右)每个关系):

When I run this code, I get the following warning spit out several times (seems to be about twice per relationship):

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数组中没有任何内容可以映射。

The strange thing is that the relationship gets set up properly (even looked at the sqlite database, and everything looks fine there) but I'm not happy with something clearly going wrong in the RestKit code, and it seems to have something to do with the bogus User mapping I create in the code above (it's empty, since there is nothing to map in the array of IDs).

我尝试了替代方案,例如当我添加关键路径映射时:

I've tried alternatives, for example when I add a key path mapping:

[userMapping mapKeyPath:@"" toAttribute:@"identifier"];

它抱怨,显然是因为关键路径是空的

It complains, obviously because the key path is empty

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 .

如果我尝试使用真正的用户 mapping

And if I try to use the real User mapping

[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试图将memberIDs数组中的ID字符串本身映射到 User 对象,这没有任何意义。我见过这样的例子,其中关系数组是一个带有键的字典列表(例如名为 id ),其中包含对另一个对象的引用ID,例如:

Seems like RestKit is trying to map the ID strings themselves in the memberIDs array to User objects, which doesn't make any sense. I've seen examples where the relationship array is a list of dictionaries with keys (e.g. called id) with the reference ID to the other object, for example:

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

但我不想以这种方式改变我的JSON(除此之外) ,我希望RestKit足够灵活,可以支持其他方式。)

But I don't want to change my JSON in that way (besides, I'm hoping RestKit is flexible enough to support the other way.)

有谁知道在RestKit中进行这种关系映射的正确方法是什么?

Does anyone know what the proper way of doing this kind of relationship mapping in RestKit is?

更新

我最后修改了REST界面以发送一个列表包含用户对象ID的字典(就像上面的最后一个例子一样),并让它工作。仍然不完全满意设置,但代码现在看起来像

I ended up modifying the REST interface to send a list of dictionaries containing the user object IDs (just like the last example above), and got that to work. Still not completely happy with the setup, but the code now looks like

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

以防万一这有助于处于类似情况的其他人。我采取的方法可能仍然存在一些问题,但到目前为止一切都很好(甚至处理无序加载,这很好) - 如果对原始问题有答案,我们仍然希望听到任何人的意见。

Just in case this helps anyone else in a similar situation. There might still be some problems with the approach I've taken, but so far so good (it even handles out of order loading, which is nice) - would still love to hear from anyone if there's an answer to my original question.

推荐答案

找到一种方法使这项工作,并且还意识到我的问题中的更新方法只应该用于嵌套对象,而不是引用的对象。这个主题让我走上正轨:(如果你正在处理RestKit中的关系,那值得一读)

Found a way to make this work, and also realized that the updated approach in my question is only supposed to be used for nested objects, not referenced objects. This thread got me on the right track: https://groups.google.com/forum/#!msg/restkit/swB1Akv2lTE/mnP2OMSqElwJ (worth reading if you're dealing with relationships in RestKit)

假设JSON仍然是小组看起来像原始的JSON:

Assume the groups JSON still looks like the original JSON:

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

还假设用户被映射到密钥路径 users (即类似于 [objectManager.mappingProvider setMapping:userMapping forKeyPath:@users]; )映射关系的正确方法如下所示:

Also assume that users are mapped to a keypath users (i.e. as in something like [objectManager.mappingProvider setMapping:userMapping forKeyPath:@"users"];) the correct way to map the relationships looks like this:

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

当我早些尝试这种方法时,困扰我的是这条线

When I had tried this approach earlier, the thing that confused me was this line

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

其中第一个关键路径是指被引用对象的关键路径映射(用户在这种情况下),而不是映射的对象内关系的关键路径(可能是成员在这种情况下)。

where the first key path is referring to the key path mapping for the objects being referenced (users in this case), not the key path of the relationship within the group object being mapped (which would have been members in this case).

通过此更改,所有关系都按预期工作,我很高兴。

With this change, all relationships work as expected and I'm happy.

这篇关于通过ID数组在RestKit中映射关系不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-19 10:12