【问题标题】:Core Data - Default Migration ( Manual )核心数据 - 默认迁移(手动)
【发布时间】:2012-02-28 12:22:14
【问题描述】:

我已经阅读了所有可能的博客和关于该主题的 SO 帖子 - 但仍然不确定发生了什么。 我也读过this,但仍然没有运气——他们的默认迁移指南很清楚,但在我的情况下不起作用。 我对 iOS 开发比较陌生,所以要温柔:)

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

数据属性 - 已删除

title 属性 - 添加

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 ),关闭了轻量级迁移。因为我是新手,所以我决定采取一些小步骤,不要让这个 reportId Int > String 改变并测试我的映射。它没有用。同理=找不到迁移的映射模型。我试图将 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”而终止应用程序,原因:“属性值的不可接受类型:属性 =“reportId”;所需类型 = NSString;给定类型 = __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”的地步,原因:“映射和源/目标模型之间不匹配” - 源模型和目标模型以及映射模型,一切看起来都应该如此。 我即将放弃并愿意丢失该报告实体中的数据..有什么办法吗?

编辑 3

所以,为了尝试一下,我将模型回滚到所有这些疯狂之前的位置,创建了新版本,其中我只进行了一项更改 - 删除了一个字段。然后我创建了映射模型并尝试使用它。 - 映射和源/目标模型之间的相同错误不匹配 - 看起来生成的映射模型在某种程度上是不好的,但是看着它 - 我没有发现任何问题。

【问题讨论】:

  • 嗨。我相信你需要为你的托管对象专门化一个 NSEntityMigrationPolicy,并在你的映射模型中设置它的名称。你做到了吗?

标签: ios core-data migration versioning


【解决方案1】:

如果您没有找到答案,我可以建议小技巧。 首先,了解为什么会发生这种情况,但是源模型、目标模型和映射模型对于相同的实体具有不同的 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];

【讨论】:

  • 谢谢谢谢谢谢!在花了将近一天的时间解决这个问题之后,您是第一个给我正确解决方案的人。我发现版本哈希不匹配(在 Version.plist 和 .cdm 之间,您可以通过使用 plutil 将其从二进制转换为 XML plist 格式来检查)。但你的代码实际上解决了这个问题。
  • 它确实工作得很好,但实际上有点冒险...... :] 我希望 Apple 能在新的 Xcode 中解决这个问题(我猜是编辑器的错)。
  • 这对我也有用。就我而言,我正在从模型 1 迁移到模型 3。
  • 哇...我想我不应该对这个不起眼的框架有问题感到惊讶。谢谢解答!!!
  • 谢谢,它有效。这是我的错误报告:openradar.appspot.com/radar?id=3022402。 @stephen 请复制它,以便 Apple 尽快修复它。
【解决方案2】:

this question 的帮助下,我解决了您的问题。

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

演示应用程序可以从here下载

【讨论】:

  • 只是为了让自己清楚 - Apple 所谓的默认迁移,不会正常工作吗?
  • 到了我有 'NSInvalidArgumentException' 的地步,原因:'映射和源/目标模型不匹配' - po 源和目标模型和映射模型,一切看起来都应该..
  • 会接受这个答案,因为它确实显示了默认/自定义迁移的正确性。在我的情况下不起作用,因为映射有问题。所以我结束了,不是版本数据库,只是杀死它并在架构不匹配时重新创建。
  • 我在 NSLog(@"is not compatible"); NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:sourceMetadata]; 之后使用你的和我的 NSManagedObjectModel 我的 sourceModel 是 nil,因为它没有进入它的循环。
猜你喜欢
  • 1970-01-01
  • 2011-09-14
  • 2011-02-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-24
  • 2011-07-22
  • 2023-03-14
  • 1970-01-01
相关资源
最近更新 更多