11

的背景

  • 具有两个托管对象模型的 Cocoa 非文档核心数据项目。
  • 模型 1 保持不变。Model 2 变了,所以想迁移店铺。
  • 我在 Xcode 中通过 Design > Data Model > Add Model Version 创建了一个新版本。
  • 版本之间的区别在于已从一对多更改为单一关系。
  • 我已经对模型进行了更改,然后保存了。
  • 我制作了一个新的映射模型,其中旧模型作为源,新模型作为目标。
  • 我已确保所有映射模型和数据模型都在编译中,并且都被复制到我的应用程序包的 Resource 文件夹中。
  • 我已经通过在 添加持久存储时使用带有NSMigratePersistentStoresAutomaticallyOption 键的字典来打开迁移。[NSNumber numberWithBool:YES]
  • 我没有合并捆绑包中的所有模型,而是指定了我要使用的两个模型(模型 1 和模型 2 的新版本)并使用modelByMergingModels:

问题

无论我做什么迁移,我都会收到错误消息:

“持久存储迁移失败,缺少源托管对象模型。”

我试过的

  • 我在每次构建后进行清洁。
  • 我已经尝试了各种组合,只有在资源中迁移到的模型、正在编译的模型,或两者兼而有之。
  • 由于错误消息暗示它找不到用于我的迁移的源模型,因此我尝试将模型的每个版本都放在 Resources 文件夹中并进行编译。
  • 通过切换回我的数据模型的原始版本,我确保我没有犯一个真正的基本错误。该应用程序运行良好。
  • 我删除了映射模型和模型的新版本,清理,然后重新创建两者。
  • 我尝试在新模型中进行不同的更改 - 改为删除实体。

我无计可施。

我不禁认为我在某个我没有看到的地方犯了一个巨大的错误。有任何想法吗?

4

6 回答 6

16

两种可能:

  1. 您应用程序中的源模型与磁盘上的实际存储不匹配。
  2. 您的映射模型与源模型不匹配。

打开Core Data 调试,您应该能够看到 Core Data 在进行迁移时正在寻找的哈希值。将这些哈希值与您存储在磁盘上的内容进行比较,看看它们是否匹配。同样,调试应该让您看到映射模型中的哈希值,以帮助您匹配所有内容。

如果只是您的映射模型未对齐,您可以告诉它从 Xcode 的设计菜单中从源代码更新。如果您缺少磁盘上存储文件的实际源模型,则可以查看版本控制系统或尝试使用自动迁移将该文件迁移到您认为是源的模型。

更新 1

更改源模型和目标模型的位置已移至编辑器窗口底部:

于 2010-03-22T12:37:23.653 回答
6

我没有合并捆绑包中的所有模型,而是指定了我要使用的两个模型(模型 1 和模型 2 的新版本)并使用 modelByMergingModels 合并它们:

这似乎不对。为什么要合并模型?您想使用模型 2 ,从模型 1迁移您的商店。

来自 NSManagedObjectModel 类参考

modelByMergingModels:

从现有模型数组创建单个模型。

您不需要对源模型(模型 1)做任何特殊/特定的事情。只要它在您的包中,自动轻量级迁移过程就会发现并使用它。

我建议放弃您在 Xcode 中创建的映射模型,因为与自动轻量级迁移相比,我已经看到了糟糕的性能。您的里程可能会有所不同,我在模型之间的更改与您的不同,但我不会感到惊讶。在捆绑包中尝试使用和不使用您自己的映射模型的时间。

 /* Inferred mapping */
 NSError *error;
 NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                          [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                          [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,nil];
 NSPersistentStore *migratedStore = [persistentStoreCoordinator addPersistentStoreWithType:nil
                                                                             configuration:nil
                                                                                       URL:self.storeURL
                                                                                   options:options
                                                                                     error:&error];
 migrationWasSuccessful = (migratedStore != nil);

您可以在代码中验证您的源模型是否可用,方法是尝试加载它并验证它不是 nil:

NSString *modelDirectoryPath = [[NSBundle mainBundle] pathForResource:@"YourModelName" ofType:@"momd"];
if (modelDirectoryPath == nil) return nil;
NSString *modelPath = [modelDirectoryPath stringByAppendingPathComponent:@"YourModelName"];
NSURL *modelFileURL = [NSURL fileURLWithPath:modelPath];
NSManagedObjectModel *modelOne = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelFileURL];
if (modelOne == nil) {
    NSLog(@"Woops, Xcode lost my source model");
}
else {
    [modelOne release];
}

这假设在您的项目中,您有一个资源“ YourModelName.xcdatamodeld ”和“ YourModelName.xcdatamodel ”。


此外,您可以检查该模型是否与您现有的迁移前持久存储兼容:

NSError *error;
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:self.storeURL error:&error];
if (storeMeta == nil) {
    // Unable to read store meta
    return NO;
}
BOOL isCompatible = [modelOne isConfiguration:nil compatibleWithStoreMetadata:storeMeta];

该代码假定您有一个方法-storeURL来指定从何处加载持久存储。

于 2010-04-01T05:01:25.947 回答
4

当我收到这个错误时,我已经更新了我的核心数据模型,但没有从我的测试手机中清除应用程序实例。这意味着保存到手机核心数据的模型与我在代码中尝试使用的模型不匹配。

我从手机中删除了该应用程序并成功重新构建/运行。

于 2019-02-06T17:50:09.260 回答
3

在尝试升级现有应用程序的核心数据模型(并迁移旧数据)时,我遇到了第三方框架正在将数据写入应用程序数据库的场景。我收到了这个错误,“找不到源商店的模型。” 因为我在尝试迁移时没有加载第三方模型,所以迁移失败。

我在解决此问题时编写了此方法(如下)。它可能对那些面临这些类型问题的人有用。

- (BOOL) checkModelCompatibilityOfStoreWithURL: (NSURL *) myStoreURL
                                 forModelNamed: (NSString *) myModelName
                                  withBasePath: (NSString *) myBasePath;
{
    NSError * error = nil;
    NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:myStoreURL error:&error];
    if (!storeMeta) {
        NSLog(@"Unable to load store metadata from URL: %@; Error = %@", myStoreURL, error);
        return NO;
    }

    NSString * modelPath = [myBasePath stringByAppendingPathComponent: myModelName];
    NSFileManager *fileManager = [NSFileManager defaultManager];
    if (![fileManager fileExistsAtPath: modelPath]) {
        // uh oh
        NSLog(@"Can't find model.");
        return NO;
    }

    NSURL * modelURL = [NSURL fileURLWithPath: modelPath];
    NSManagedObjectModel * model = [[[NSManagedObjectModel alloc] initWithContentsOfURL: modelURL] autorelease];
    BOOL result = [model isConfiguration: nil compatibleWithStoreMetadata: storeMeta];

    NSLog(@"Tested model, %@, is%@ compatible with Database", modelPath, result ? @"" : @" ~not~");

    return result;
}

此代码段将获取商店的元数据。

NSError *error = nil;
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSDictionary *storeMeta = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:nil URL:storeUrl error:&error];
NSLog(@"%@", [storeMeta objectForKey: @"NSStoreModelVersionHashes"]);

VersionInfo.plist(存储在编译后的应用程序包中)包含与模型中的各种实体相关联的哈希值(base64 编码)。同样,数据存储区 (Z_METADATA.Z_PLIST) 中的 BLOB 列包含一个二进制编码的属性列表,其中包含与数据关联的每个实体的哈希值(也是 base64 编码的)。

NSManagedObjectModel 上的 -entitiesByName 方法对于转储特定模型中存在的实体和哈希很有用。

于 2011-06-02T20:56:51.783 回答
1

我有一个类似的问题。我用过+modelByMergeingModels:,但我没有使用映射模型。但是,合并模型不适用于轻量级数据迁移。

来自苹果文档:

要执行自动轻量级迁移,Core Data 需要能够在运行时找到源和目标托管对象模型本身。

如果您使用+modelByMergeingModels:,则用于目标模型。但是 Core Data 将无法找到源模型。源模型是+modelByMergeingModels:在旧版本的应用程序中创建的,Core Data 确实尝试合并模型以找出源模型。

我最终做的是,我(手动).xcdatamodeld通过编辑模型的 XML 文件创建了一个新的合并,将其添加到项目中,.xcdatamodeld从 Compile Sources 中删除了单独的 s,而不是使用+modelByMergeingModels:useNSManagedObjectModel-initWithContentsOfURL:URL新的合并模型。我可能会创建一个脚本,将来会自动合并模型。

于 2014-11-20T17:52:54.530 回答
1

如果您在 Mac Catalyst 应用程序中遇到此问题,则需要删除可在 ~/Library/Containers/name-of-app 中找到的存储数据

于 2021-08-18T08:15:01.493 回答