自定义NSEntityMigrationPolicy关系

时间:2012-06-25 13:36:08

标签: iphone core-data core-data-migration

我正在尝试使用自定义NSEntityMigrationPolicy进行数据库升级。这就是我的数据模型现在的样子以及预期的结果:

  A <-------->> B   ( 1 A -> many B ) 

我想要一个新的C实体,它将“破坏”某些子集中的B类型对象:

  A <-------->> C <------->> B  ( 1 A can have many C, each C can have many B )

我为实体A制作了一个自定义NSEntityMigrationPolicy。我为createDestinationInstancesForSourceInstance:entityMapping:manager:error:中的每个A创建了一些C实体,但我不知道如何处理A和B之间的关系。

在文档中,他们说要以某种方式使用createRelationshipsForDestinationInstance创建新的关系。但是,对于这种情况,我没有找到任何暗示性的例子。我想可能是A&lt; - &gt;&gt;可以在此处创建C关系,但是在目的地上下文中可能还不存在B以创建C - > B关系。如何进行这样的迁移?请帮助:)

谢谢!

1 个答案:

答案 0 :(得分:9)

基本方法是

  1. 创建迁移A-to-C的策略
  2. 创建迁移A-to-A
  3. 的政策
  4. 创建用于迁移B-to-B的策略
  5. 以正确的顺序执行此操作非常重要。

    由于数据库中不存在C,您必须做一个小技巧:NSMigrationManager可以存储userInfo。此userInfo字典在整个迁移过程中都可用。因此,您可以在userInfo dict中存储您在A-to-C中创建的每个C对象。您需要在A上具有唯一标识符属性以将其存储为键,并将相应的C对象设置为值。在第三次迁移(B-to-C)中,您可以访问相应的C对象并将其分配给B.

    <强> 1。 A-to-C:根据每个现有的A对象创建新的C对象。

    beginEntityMapping:manager:error:中创建您的初始NSMutableDictionary并将其分配给NSMigrationManager的userInfo属性。

    createDestinationInstancesForSourceInstance:entityMapping:manager:error:中执行以下操作:

    - (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error
    {
        NSMutableDictionary *cObjects = (NSMutableDictionary *)[manager userInfo];
        NSObject *aUniqueIdentifierForEveryAObject = [sInstance valueForKey:@"aUniqueIdentifier"];
    
        NSManagedObject *destinationC = nil;
        if ([[cObjects allKeys] containObject:aUniqueIdentifierForEveryAObject])
        {
            newC = [userInfo objectForKey:aUniqueIdentifierForEveryAObject];
        }
        else
        {
            newC = [NSEntityDescription insertNewObjectForEntityForName:@"C" inManagedObjectContext:[manager destinationContext]];
    
            // Assign instance A (sInstance) to the newC and update the userInfo
            [newC setValue:sInstance forKey:@"a"];
            [cObjects setObject:newC forKey:aUniqueIdentifierForEveryAObject];
        }
    
        [manager associateSourceInstance:sInstance withDestinationInstance:destinationC forEntityMapping:mapping];
        return YES;
    }
    
    - (BOOL)createRelationshipsForDestinationInstance:(NSManagedObject*)dInstance entityMapping:(NSEntityMapping*)mapping manager:(NSMigrationManager*)manager error:(NSError**)error
    {
        return YES;
    }
    

    <强> 2。 A-to-A:迁移所有A对象

    您可以在此处对A的属性进行一些其他调整。重要的是,无论是否进行属性更改,都要创建此迁移,因为自动迁移已关闭。如果您没有任何更改,只需在映射模型编辑器中创建实体映射。

    第3。 B到B:迁移所有B对象并分配新的C对象

    分配新的C对象。你不能在createRelationships...中这样做,因为你需要A对象和它的唯一标识符来从userInfo dict中获取适当的C。

    - (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error
    {
        id destinationB = [NSEntityDescription insertNewObjectForEntityForName:@"B" inManagedObjectContext:[manager destinationContext]];
        NSMutableDictionary *userInfo = (NSMutableDictionary *)[manager userInfo];
        NSMutableDictionary *cObjects = (NSMutableDictionary *)[userInfo valueForKey:kCObjects];
        A *anA = [sInstance valueForKey:@"a"];
        NSObject *aUniqueIdentifierForA = [anA valueForKey:@"aUniqueIdentifier"];
        C *newC = [userInfo objectForKey:aUniqueIdentifierForA];
        [destinationB setValue:newC forKey:@"c"];
    
        // Migrate all other attributes here
        [destinationB setValue:... forKey:...];
    
        [manager associateSourceInstance:sInstance destinationB forEntityMapping:mapping];
    
        return YES;
    }
    
    - (BOOL)createRelationshipsForDestinationInstance:(NSManagedObject *)dInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error
    {
        return YES;
    }
    

    我没有对此进行过测试,但基本方法应该可行。


    <强>更新

    步骤1中出现错误:A-to-C。

    // WRONG
    [cObjects setObject:newC forKey:sInstance];
    
    // UPDATED
    [newC setValue:sInstance forKey:@"a"];
    [cObjects setObject:newC forKey:aUniqueIdentifierForEveryAObject];