CoreData中的自参考数据对象 [英] Self-Referencing Data Object in CoreData

查看:163
本文介绍了CoreData中的自参考数据对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从一生的SQL心理切换到CoreData,它不是没有几个打嗝。目前正在踢我的东西是创建一个自引用对象。请允许我解释。

I'm making the mental switch from a lifetime of SQL to CoreData and it's not without a few hiccups. The thing that's kicking me at the moment is creating a self-referencing object. Allow me to explain.

使用SQL术语,我有一个表,其中包含一个过程中的步骤。为了保持简单,我会说表格包含两个信息 - 步骤的名称和它后面的步骤(它可能或可能不是表中的下一个记录)。进程中的所有步骤都存储在一个表中。每个步骤将总是有一个步骤,它后。

Using SQL terminology, I have a table that contains the steps in a process. To keep it simple, I'll say the table holds two pieces of information - the name of the step and the step that comes after it (which may or may not be the next record in the table). All steps in the process are stored in a single table. Each step will ALWAYS have one step that comes after it. But not all steps have a step that comes before it.

换句话说,它应该看起来像这样:

In other words, it should look something like this:

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

In the SQL world, I would make a single table with an identity field, the name, and a foreign key referencing its own identity field (I guess that would be a domestic key?), thusly:

但是,例如身份字段。也不是有一个选择查询我可以创建来拉我需要的信息。

However, with relationships, there is no such thing as an identity field. Nor is there a select query I can create to pull the info I need.

那么什么是最好的方法创建一个实体做同样的事情?我试图创建一个反向自己的关系,这是一个难以调试的灾难。其他选项是什么?

So what is the best approach for creating an Entity that does the same thing? I tried creating a relationship that inverted to itself and that turned out to be a hard to debug disaster. What are the other options?

谢谢!

推荐答案

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

Ah! You provided the vital clue, Martin.

我试过代码示例,但是这不行。它结束了创建一切的重复,因为thingA和thingB插入到表中。但是,图表实际上给了我什么我认为可能是关键。以前,我试过分配nextStep作为它自己的反向关系,这只是bonkers。

I tried the code sample, but that didn't quite work. It ended up creating duplicates of everything because both thingA and thingB got inserted into the table. However, the diagram actually gave me what I think might be the key. Previously I had tried assigning nextStep as its own inverse relationship, which was just bonkers. But just adding previousSteps and setting that to Many while nextStep was set to One seems to have led to the solution.

这是我最后为关系创建的:

Here's what I ended up creating for the relationships:

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

Here is the plist I used to populate the Steps entity (intended to be run on first-time use or when the database is reset):

现在这里是实体群常规。这是昨天让我起来的东西:

And now here is the entity population routine. This is what was tripping me up yesterday:

- (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)创建一个NSMutableDictionary来保存迭代的结果,使用stepName作为Key,以便以后可以引用。

Here's the key. At (1) create an NSMutableDictionary to hold the results of the iteration, using the stepName as the Key so it can be referred to later on.

While(2)枚举通过plist内容,(3)创建第一个NSEntityDescription就像你所做的那样。

While (2) enumerating through the plist contents, (3) create the first NSEntityDescription just as you did. But instead of creating the second one, (4) add it to the dictionary.

一旦初始枚举完成,(5)第二次返回。但是这次,通过引用原始对象本身创建关系。有意义吗?

Once the initial enumeration is done, (5) go back through a second time. But this time, create the relationships by referring to the original objects themselves. Make sense?

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

After that, save the context as normal. The result, in this case, is 5 records, each referencing another record in the same entity, with no conflicts or duplicates.

现在的重要问题:如何将此标记为已回答?谁获得复选标记?

Now the important question: how do I mark this as answered? Who gets the checkmark?

这篇关于CoreData中的自参考数据对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆