我有一个来自rails应用程序的地方列表,我正试图在iOS5应用程序中导入。每个地方都有一个父母,这是一个地方本身。
我正在尝试使用字典
导入带有Core Data的JSON数据- (void)initWithDictionary:(NSDictionary *)dictionary {
self.placeId = [dictionary valueForKey:@"id"];
id parent = [dictionary objectForKey:@"parent"];
if (parent && parent != [NSNull null]) {
NSDictionary *parentDictionary = parent;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"placeId = %@", [parentDictionary objectForKey:@"id"]];
NSArray *matching = fetchedWithPredicate(@"Place", self.managedObjectContext, predicate, nil);
if ([matching count] > 0) {
self.parent = [matching objectAtIndex:0];
} else {
self.parent = [NSEntityDescription insertNewObjectForEntityForName:@"Place" inManagedObjectContext:self.managedObjectContext];
[self.parent initWithDictionary:parentDictionary];
}
}
}
fetchedWithPredicate是一个定义为
的方法NSArray* fetchedWithPredicate(NSString *entityName, NSManagedObjectContext *context, NSPredicate *predicate, NSError **error) {
NSFetchRequest *request = [[NSFetchRequest alloc] init];
[request setIncludesPendingChanges:YES];
NSEntityDescription *entity = [NSEntityDescription entityForName:entityName inManagedObjectContext:context];
[request setEntity:entity];
[request setPredicate:predicate];
NSArray *result = [context executeFetchRequest:request error:error];
return result;
}
我在Place.m中也有一个验证方法,以确保我不创建与placeId相同的位置(placeId是服务器端的id)。
- (BOOL)validatePlaceId:(id *)value error:(NSError **)error {
if (*value == nil)
return YES;
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"placeId = %@ AND (NOT self IN %@)", *value, [NSArray arrayWithObject:self]];
NSArray *matching = fetchedWithPredicate(@"Place", self.managedObjectContext, predicate, error);
if ([matching count] > 0) {
return NO;
}
else {
return YES;
}
}
要导入数据,我从服务器获取所有位置,以JSON格式返回。 每个Place都有自己的信息,以及一个包含父元素信息的子节点,这意味着多个子节点的每个父节点都会多次出现。它看起来像
{ "id": 73,
"name": "Some place",
"parent": { "id": 2,
"name": "Parent's name"}
}
我认为上面的代码做了一些“查找或创建”,包含未保存的更改,但是没有问题。 但它仍然试图为某些地方创建多个条目(并且因为已经进行了验证而失败)。更深入地看,它确实为同一个placeId(不同的指针)插入了不同的核心数据对象,但我不知道为什么。
由于
答案 0 :(得分:3)
听起来你已经有了一个唯一的id索引(很明显很好)。我认为您不是在将新插入的创建保存到核心数据之前,而是希望通过fetch返回它。简单(如果可能不太高性能,取决于有很多行)将在插入/插入每个对象后立即添加saveContext
调用。
另一种方法是在两次传递中完成,首先完全在内存中创建一个单独的字典,其中键是id,对象是值。这样你就可以确保每个id只在那里一次。在他们全部进入该词典之后,您可以轻松地(或者更容易地)将它们全部添加到Core Data中。
答案 1 :(得分:0)
因此,经过一番调查后,这是因为我按名称对数据进行排序......
因此,如果一个地方A有5个孩子,其中3个人的名字在A的名字之前,那么代码就会:
现在我们有2个对象A,一个有父对象,另一个没有父对象,Core Data认为它有2个对象。
简单的出路:我的树是嵌套的,所以我只需要按左边的值排序,这样我就会在孩子面前创建父母。
“按名称排序”不是我的描述的一部分,因此我将scc的答案视为已接受:)