2012-12-17 257 views
2

我读过名为Core Data Model Versioning and Data Migration Programming Guide的文档。但我仍然没有很多技巧。所以我想发布我遇到的一个例子。通过示例迁移核心数据

我有两个实体RuleInstanceRule有一个名为identifier的属性。 Instance也有一个名为identifier的属性。

Rule有一个唯一的标识符,每个实例有一个identifier相同的Rules之一。这就像RuleInstance(应该是)之间的很多关系。

在我的数据模型的新版本中,我想在RuleInstance之间建立一对多的关系,我该如何进行迁移?

+0

谢谢tkanzakic,下次我会在我的格式上做得很好:) – CarmeloS

回答

5

我已经想通了。

NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
          [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
          [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, 
          nil]; 

    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 

configuration:nil URL:storeURL options:options error:&error]) 
{ 
    //other code handle error 
} 

创建Xcode的一个映射模型,设置它的源代码版本和目标版本: 第一,创造持久存储协调时,设置这些选项。

创建一个NSEntityMigrationPolicy的子类,将其命名为MyPolicy,覆盖该方法。

-(BOOL)createRelationshipsForDestinationInstance:(NSManagedObject *)dInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error 

当调用此方法时,所有managedObjects已在目标上下文中创建,但它们的关系不是。 在这个方法中,检查什么实体是dInstance,并为它建立关系。

使用Xcode,在您的映射模型中,将名为InstanceToInstance的ENTITY MAPPINGS的映射策略设置为MyPolicy

此方法将针对每个实例对象调用一次。 我的问题,我应该这样做:

-(BOOL)createRelationshipsForDestinationInstance:(NSManagedObject *)dInstance entityMapping:(NSEntityMapping *)mapping manager:(NSMigrationManager *)manager error:(NSError **)error{ 
    NSError *superError = nil; 
    BOOL mappingSuccess = [super createRelationshipsForDestinationInstance:dInstance entityMapping:mapping manager:manager error:&superError]; 
    if ([dInstance.entity.name isEqualToString:@"Rule"]){ 
     Instance *instance = (Instance*)dInstance; 
     NSFetchRequest *fetch = [[NSFetchRequest alloc] initWithEntityName:@"Instance"]; 
     fetch.predicate = [NSPredicate predicateWithFormat:@"identifier == %@",instance.identifier]; 
     NSArray *result = [manager.destinationContext executeFetchRequest:fetch]; 
     Rule *rule = [result objectAtIndex:0]; 
     instance.rule = rule; 
    } 
    return YES; 
} 

然后,规则和实例之间的关系船将要创建的应用程序启动时。

另请注意,由NSEntityMigrationPolicy的子类创建的关系不需要在xcode的迁移策略编辑窗口中设置值表达式,只需将其留空即可。

+0

感谢这个美妙的解决方案。我唯一的问题是,我在谓词中为'instance.identifier'获得了'NaN'。任何想法为什么发生这种情况? http://stackoverflow.com/questions/23021817/description-of-nsmanagedobject-shows-values-but-accessing-them-shows-nan – Houman

3

看来您可以使用轻量级迁移来更改关系。

创建新版本后,只需更改或添加关系即可。

详情请看这里LightweightMigration

所有你需要做的是选项添加到您的persistentStoreCoordinator方法在你的委托。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 

    if (persistentStoreCoordinator != nil) { 
    return persistentStoreCoordinator; 
    } 

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"YOURDB.sqlite"]]; 

    // handle db upgrade 
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys: 
    [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
    [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption, nil]; 

    NSError *error = nil; 
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel: [self managedObjectModel]]; 
    if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) { 
    // Handle error 
    } 

    return persistentStoreCoordinator; 
} 

然后,在更改模型并选择它作为活动模式后,只需重新安装应用。 就是这样。

+0

谢谢,但真实情况比这更复杂,这只是一个例子,向我介绍手动迁移。 – CarmeloS

+0

再次。你需要的只是添加一段关系吗? – shannoga

+0

是的。只是增加关系。 – CarmeloS