2012-03-05 77 views
4

我有一個列表,我試圖在iOS5應用中導入一個rails應用程序。每個地方都有一個父母,這是一個地方。核心數據:使用查找或插入/重複條目導入樹結構

我試圖使用字典

- (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導入與核心數據即JSON數據是被定義爲這樣

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格式返回。 每個地方都有自己的信息,外加一個包含父母信息的子節點,這意味着多個孩子的每個父母將多次出現。它看起來像

{ "id": 73, 
    "name": "Some place", 
    "parent": { "id": 2, 
       "name": "Parent's name"} 
} 

我想上面的代碼確實種類的「尋找或創造」,以獲取包括未保存的更改,會好的。 但它仍然嘗試爲某些地方創建多個條目(並且由於存在驗證而未能成功)。更深入地看,它確實爲同一個placeId(不同的指針)插入了不同的核心數據對象,但我不知道爲什麼。

感謝

回答

3

這聽起來像你已經有ID的唯一索引(這是很好很明顯)。我認爲這是因爲你沒有將新插入的作品保存到核心數據中,然後期待它通過獲取進行返回。簡單的(如果可能不是太高性能,取決於有很多行)將在每個對象被插入/插入後添加一個saveContext調用。

另一種方法是在兩遍中完成它,首先完全在內存中創建一個單獨的字典,其中鍵是id,對象是值。這樣你就可以確保每個ID只在那裏一次。在他們都在該字典中之後,您可以輕鬆(或者更簡單地)將它們全部添加到Core Data中。

+0

我認爲有「setIncludesPendingChanges:YES」在我的FETCH結果足以讓在對象即使我沒有保存上下文,當前上下文也是如此。你知道這是爲什麼嗎? 除非有答案,否則你會建議使用單獨的字典。 – Nycen 2012-03-06 03:13:00

+1

我認爲pendingChanges(在這裏猜測)可能只知道是否爲每個循環添加了定期的[[moc processPendingChanges]]調用,但如果您在主線程/運行循環中則應該定期調用它。 – 2012-03-06 13:10:07

0

所以,更有點調查後,這是由於這樣的事實,我是按名稱排序我的數據...

所以,如果一個地方有5個孩子,其中有3例,這是一個名字之前的名稱,代碼:

  1. 創建這些3個孩子與父母沒有任何父本身(因爲我的JSON不返回有關父母的父母的相關信息)
  2. 創建一個
  3. 創建另外兩個A作爲父母的孩子(可能是因爲但是這並沒有改變結論),所以父母有父母

現在我們有2個對象A,一個帶有父母,另一個沒有父母,其中的核心數據考慮有2個對象。

簡單的方法:我的樹是一個嵌套集合,所以我只需要按左值排序,這樣我就會在孩子之前創建父母。

的「按名稱排序」不是我描述的一部分,所以我會離開SCC的答案接受:)