关于Objective C:magicalrecord删除未导入的数据

magicalrecord deleting non-imported data

想象一下CoreData中的以下关系

1
Recipe < --- >> Ingredient

我正在使用MagicalRecord定期使用本地CoreData数据库导入服务器数据库(JSON API)。

因此,如果我用Ingredient 1导入Recipe 1像这样:

1
2
3
4
5
6
7
{
  id:1,
  name:"Recipe 1",
  ingredients: [{
    name: 'Ingredient 1'
  }]
}

因此,MagicalRecord创建了两个实体并将它们链接在一起。

当服务器更改为以下内容时,出现此问题:

1
2
3
4
5
6
7
{
  id:1,
  name:"Recipe 1",
  ingredients: [{
    name: 'Ingredient 2' <-- Notice here
  }]
}

MagicalRecord所做的是创建Ingredient 2记录(正确),将其链接为Recipe 1(正确)的唯一成分。但是,如果我搜索"成分",则会在CoreData数据库中找到2条记录。

问题是,在导入和删除对象时是否可以跟踪"已删除"的对象?


我已经按照以下步骤解决了这个问题。

  • 在您的核心数据存储上运行查询,该查询将返回您期望的任何给定服务器请求值。查找查询期望由服务器返回的每个对象的所有objectID。
  • 发出服务器请求并导入数据。
  • 保存之前,从刚用于导入数据的上下文中获取所有更新的对象。
  • 删除原始objectID列表中未包含在更新的objectID列表中的任何对象
  • 对于任何给定请求,此方法均应实现所需的行为。请注意,您仍然可能会删除其他地方引用的记录,因此,仅当可以由其他将来的请求重新创建它们时,才使用此方法。

    导入代码

    1
    2
    3
    4
    5
    6
    7
    NSArray *existingObjectIDs = [self existingObjectIDsForYourQuery];

    [MagicalRecord saveWithBlock:^(NSManagedObjectContext *localContext) {
                        [Recipe MR_importFromObject:response inContext:localContext];
                        NSArray *objectIDs = [[[localContext updatedObjects] allObjects] valueForKey:@"objectID"];
                        [self deleteLocalObjectsWithObjectIDs:existingObjectIDs excludingImportedObjectIDs:objectIDs];
    }];

    删除代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    - (void)deleteLocalObjectsWithObjectIDs:(NSArray *)existingObjectIDs excludingImportedObjectIDs:(NSArray *)importedObjectIDs {
        NSMutableArray *objectsToDelete = [NSMutableArray arrayWithArray:existingObjectIDs];

        for ( NSManagedObjectID *objectID in importedObjectIDs ) {
            [objectsToDelete removeObject:objectID];
        }

        [MagicalRecord saveWithBlockAndWait:^(NSManagedObjectContext *localContext) {
            for ( NSManagedObjectID *objectID in objectsToDelete ) {
                NSManagedObject *object = [localContext existingObjectWithID:objectID error:nil];

                if ( object ) {
                    [localContext deleteObject:object];
                }
            }
        }];
    }

    这里的真正问题是MagicalRecord似乎正在导入重复项。这个问题应该在最近的更新中已经解决,但是,如果您仍然遇到问题,建议您在项目问题页面上打开工单


    如果这是用作主键的服务器,则不能仅更改服务器上的Ingredient名称。 MagicalRecord和Core Data不知道更新了哪个记录,因为它知道不存在具有该名称的Ingredient,它将为您创建一个新记录并映射Recipe中的关系。您必须手动删除本地应用程序数据库中JSON有效负载中不存在的任何记录。

    请考虑以下内容:

    您的Ingredient对象没有主键。您必须让MagicalRecord知道主键是什么(当不存在" ingredientID "属性时。

    您可以通过进入核心数据模型并选择Ingredient实体来执行此操作。接下来,在数据模型检查器的用户信息中添加一个" relatedByAttribute "键,并以" name "作为值。

    接下来进入您的Recipe实体,为Ingredient选择关系,并在用户字典中为该关系添加一个" relatedByAttribute "键和" name "值。这样,MagicalRecord现在知道可以通过" name "属性查找任何现有的Ingredient记录,并且如果存在的话,它将映射到现有的记录,其他人将创建一个新实体并将Recipe链接到该记录。<铅>

    您可以在此处阅读更多信息:http://www.cimgf.com/2012/05/29/importing-data-made-easy/,特别是"与按键有关"部分。

    同样,如上所述,

    您仅更新了名称,这意味着您可能应该删除当前Recipe的所有Ingredient。如果在服务器上删除对象,则还需要在本地数据库中删除它。

    如果仍然有问题,建议您在Recipe上创建一个类别类,在其中您手动查找与名称匹配的任何记录,并相应地创建/更新。但是不要忘记删除有效负载中不存在但本地存在的记录。