自定义NSEntityMigrationPolicy关系

Tem*_*lar 5 iphone core-data core-data-migration

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

  A <-------->> B   ( 1 A -> many B ) 
Run Code Online (Sandbox Code Playgroud)

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

  A <-------->> C <------->> B  ( 1 A can have many C, each C can have many B )
Run Code Online (Sandbox Code Playgroud)

NSEntityMigrationPolicy为实体A 做了一个习惯.我为每个A创建了一些C实体createDestinationInstancesForSourceInstance:entityMapping:manager:error:,但是我对如何处理A和B之间的关系感到困惑.

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

谢谢 !

Flo*_*lke 9

基本方法是

  1. 创建用于迁移A-to-C的策略
  2. 创建用于迁移A-to-A的策略
  3. 创建用于迁移B到B的策略

以正确的顺序执行它非常重要.

由于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;
}
Run Code Online (Sandbox Code Playgroud)

2. A-to-A:迁移所有A对象

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

3. B-to-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;
}
Run Code Online (Sandbox Code Playgroud)

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


UPDATE

步骤1中有一个错误:A到C.

// WRONG
[cObjects setObject:newC forKey:sInstance];

// UPDATED
[newC setValue:sInstance forKey:@"a"];
[cObjects setObject:newC forKey:aUniqueIdentifierForEveryAObject];
Run Code Online (Sandbox Code Playgroud)