核心数据 - 默认迁移(手动)

时间:2012-02-07 02:03:58

标签: ios core-data migration versioning

我已经阅读了所有可能的博客和关于这个主题的SO帖子 - 但仍然不确定发生了什么。 我还阅读this但仍然没有运气 - 他们的默认迁移指南有点明确,但在我的情况下不起作用。 我对iOS开发比较陌生,所以请保持温和:)

情况如下: 在我的应用程序(iOS)中名为Report的实体上,需要进行以下更改:

数据属性 - 已删除

标题属性 - 已添加<​​/ p> 需要将

reportId 属性从Integer 16更改为String。这就是造成我问题的原因。 我确实从当前版本创建了我的数据模型的新版本并修改了属性。

首先是应用程序中的一些方法:

- (NSManagedObjectModel *)managedObjectModel
{
    if (__managedObjectModel != nil)
    {
        return __managedObjectModel;
    }
    NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"App" withExtension:@"momd"];
    __managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];    
    return __managedObjectModel;
}

然后

/**
 Returns the persistent store coordinator for the application.
 If the coordinator doesn't already exist, it is created and the application's store added to it.
 */
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil)
    {
        return __persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"App.sqlite"];
    NSError *error = nil;

    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    NSLog(@"Which Current Version is our .xcdatamodeld file set to? %@", [[self managedObjectModel] versionIdentifiers]);
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:  
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption, 
//Commented for manual migration [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,  
                             nil];  


    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
    {

        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator
}

首先,我尝试过轻量级迁移。它失败了

reason=Can't find mapping model for migration

然后我做了以下尝试:将reportId属性恢复到原来的状态(整数16,保持模型中的其他两个变化。轻量级迁移工作正常。

好吧,我想,它可能需要手动映射才能处理数据类型更改。 所以,我已经创建了映射模型(我试图将reportId设置为“”和source.reportId),关闭了轻量级迁移。由于我是新手,我决定采取婴儿步骤,不要做这个报告.Id Int&gt;字符串更改,然后测试我的映射。它没有用。出于同样的原因=无法找到迁移的映射模型。我试图将reportId更改为String,因为它应该是 - 相同的结果。它几乎让我觉得我的映射模型完全被忽略了。事实上我已经尝试删除它 - 同样的结果同样的错误。 我到底错过了什么?

                      ## EDIT ##

好的,我需要深究这一点,我已经下载了Mihai放在一起的应用程序(谢谢!)并开始玩它。 我已修改持久性存储协调器以匹配“默认迁移”所具有的任何内容

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (__persistentStoreCoordinator != nil)
    {
        return __persistentStoreCoordinator;
    }

    NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"TestData.sqlite"];

    NSError *error = nil;
    __persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

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

    if (![__persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:options error:&error])
    {
        NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
        abort();
    }    

    return __persistentStoreCoordinator;
}

我得到的错误对我来说完全有意义。它基本上找到了正确的映射模型并尝试匹配它并给出了非常有效的错误。     2012-02-07 10:47:39.246 TestData [2008:707] ***由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'属性的值不可接受的类型:property =“reportId”;期望的类型= NSString;给定type = __NSCFNumber;值= 1。'

在我的情况下,我的转储看起来像这样(只是日志的一小部分):

   Report = "(<NSEntityDescription: 0x1708d0>) name Report, managedObjectClassName Report, renamingIdentifier Report, isAbstract 0, superentity name (null), properties {\n    action = \"(<NSAttributeDescription: 0x170a30>), name action, isOptional 1, isTransient 0, entity Report, renamingIdentifier action, validation predicates (\\n), warnings (\\n), versionHashModifier (null)\\n userInfo {\\n}, attributeType 100 , attributeValueClassName NSNumber, defaultValue 0\";\n    data = \"(<NSAttributeDescription: 0x1709e0>), name data, isOptional 1, isTransient 0, entity Report, renamingIdentifier data, validation predicates (\\n), warnings (\\n), versionHashModifier (null)\\n userInfo {\\n}, attributeType 700 , attributeValueClassName NSString, defaultValue (null)\";\n    reportId = \"(<NSAttributeDescription: 0x170a80>), name reportId, isOptional 1, isTransient 0, entity Report, renamingIdentifier reportId, validation predicates (\\n), warnings (\\n), versionHashModifier (null)\\n userInfo {\\n}, attributeType 100 , attributeValueClassName NSNumber, defaultValue 0\";\n    timestamp = \"(<NSAttributeDescription: 0x170ad0>), name timestamp, isOptional 1, isTransient 0, entity Report, renamingIdentifier timestamp, validation predicates (\\n), warnings (\\n), versionHashModifier (null)\\n userInfo {\\n}, attributeType 900 , attributeValueClassName NSDate, defaultValue (null)\";\n    type = \"(<NSAttributeDescription: 0x170990>), name type, isOptional 1, isTransient 0, entity Report, renamingIdentifier type, validation predicates (\\n), warnings (\\n), versionHashModifier (null)\\n userInfo {\\n}, attributeType 100 , attributeValueClassName NSNumber, defaultValue 0\";\n}, subentities {\n}, userInfo {\n}, versionHashModifier (null)";
}, fetch request templates {
}, reason=Can't find mapping model for migration}, {

编辑2

到了我有'NSInvalidArgumentException'的原因:原因:'映射和源/目标模型之间不匹配' - po源和目标模型以及映射模型,一切看起来都应该如此。 我即将放弃并愿意放弃该报告实体中的数据。有没有办法做到这一点?

编辑3

所以,只是为了尝试一下,我已经将我的模型回滚到所有这些疯狂之前的地方,创建了我只做了一次改变的新版本 - 放弃了一个字段。然后我创建了映射模型并尝试使用它。 - 相同的错误映射和源/目标模型之间不匹配 - 看起来生成的映射模型不知何故,但看着它 - 我没有看到任何问题。

2 个答案:

答案 0 :(得分:23)

如果你没有找到答案我可以提出小伎俩。 首先,idk为什么会发生这种情况,但是源模型,目标模型和映射模型对于相同的实体具有不同的versionHashes值。

我编程修正了他们并且发生了迁移。

 NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"Model" withExtension:@"cdm"];
 NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];

 NSArray *newEntityMappings = [NSArray arrayWithArray:mappingModel.entityMappings];
 for (NSEntityMapping *entityMapping in newEntityMappings) {

[entityMapping setSourceEntityVersionHash:[sourceModel.entityVersionHashesByName     valueForKey:entityMapping.sourceEntityName]];
[entityMapping setDestinationEntityVersionHash:[destinationModel.entityVersionHashesByName valueForKey:entityMapping.destinationEntityName]];
        }
mappingModel.entityMappings = newEntityMappings;

        BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL
                                                   type:sourceStoreType
                                                options:nil
                                       withMappingModel:mappingModel
                                       toDestinationURL:destinationStoreURL
                                        destinationType:destinationStoreType
                                     destinationOptions:nil
                                                  error:&error];

答案 1 :(得分:4)

this question的帮助下,我得解决你的问题。

我已经将基于默认主/详细模板的演示应用程序与核心数据放在一起。首次运行时,请确保在“TestData.xcdatamodeld”中选择了“TestData”模型。添加一些行,然后转到“TestData 2.xcdatamodel”,迁移将进行适当的更改。

可以从here

下载演示应用