手动核心数据架构迁移没有“文档已更改”警告?

时间:2008-12-19 04:04:37

标签: macos core-data migration mapping-model datamodel

我的基于Core Data文档的应用程序(仅限10.5)的数据模型位于 框架,因此使用Core Data映射进行自动模式升级 模型似乎不起作用。它似乎是核心数据机制 没有找到合适的数据模型或映射模型 不在应用程序的主要包中。所以,而不是使用自动 迁移,我正在手动运行迁移 我的configurePersistentStoreCoordinatorForURL:ofType:... NSPersistenDocument子类(下面的代码)。我迁移持久化 存储到临时文件,然后覆盖现有文件 迁移成功。然后该文档出现错误 消息“此文档的文件已被其他应用程序更改 因为你打开或保存它。“当我试图保存时。就像其他人一样 列表已经指出,这是由于我的修改了 文件的文件“背后”。我尝试更新文档 文件修改日期,如下所示,但我得到一个错误对话框 消息“文档的位置”test.ovproj“不能 确定。“当我试图保存时。我不太确定原因 错误,但为另一个交易一个不必要的消息(在这种情况下) 不是我想要的。

有人可以提供一些指导吗?有没有办法手动升级 文档的持久存储的模式,而不触发其中一个 这些(在案例中不必要)警告?

用于升级子类中的数据存储的代码 -configurePersistentStoreCoordinatorForURL:ofType:...

if(upgradeNeeded) {
           NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:VUIModelBundles() orStoreMetadata:meta];

           if(sourceModel == nil) {
               *error = [NSError errorWithDomain:VUIErrorDomainn ode:VUICoreDataErrorCode localizedReason:BWLocalizedString(@"Unable to find original data model for project.")];
               return NO;
           }

           NSManagedObjectModel *destinationModel = [self managedObjectModel];

           NSMigrationManager *migrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel destinationModel:destinationModel];
           NSMappingModel *mappingModel = [NSMappingModel mappingModelFromBundles:VUIModelBundles() forSourceModel:sourceModel destinationModel:destinationModel];
           if(mappingModel == nil) {
               *error = [NSError errorWithDomain:VUIErrorDomain code:VUICoreDataErrorCode localizedReason:BWLocalizedString(@"Unable to find mapping model to convert project to most recent project format.")];
               return NO;
           }

           @try {
               //move file to backup
               NSAssert([url isFileURL], @"store url is not a file URL");

               NSString *tmpPath = [NSString tempFilePath];
               id storeType = [meta objectForKey:NSStoreTypeKey];
               if(![migrationManager migrateStoreFromURL:url
                                                    type:storeType
                                                 options:storeOptions
                                        withMappingModel:mappingModel
                                       toDestinationURL:[NSURLfileURLWithPath:tmpPath]
                                         destinationType:storeType
                                      destinationOptions:storeOptions
                                                   error:error]) {

                   return NO;
               } else {
                   //replace old with new
                   if(![[NSFileManager defaultManager] removeItemAtPath:[url path] error:error] ||
                      ![[NSFileManager defaultManager] moveItemAtPath:tmpPath toPath:[url path] error:error]) {
                       return NO;
                   }

                   // update document file modification date to prevent warning (#292)
                   NSDate *newModificationDate = [[[NSFileManager defaultManager] fileAttributesAtPath:[url path] traverseLink:NO] bjectForKey:NSFileModificationDate];
                   [self setFileModificationDate:newModificationDate];
               }
           }
           @finally {
               [migrationManager release];
           }
       }
   }

   return [super configurePersistentStoreCoordinatorForURL:url ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];

3 个答案:

答案 0 :(得分:1)

我没有遇到过这种特殊情况,但我有一些猜测。首先,不要使用-removeItemAtPath:和-moveItemAtPath:当您想切换文件时,请改用FSExchangeObjects()函数。 NSDocument使用FSRefs来跟踪文件,除非你使用FSExchangeObjects(),否则它会意识到它正在查看一个完全不同的文件。

其次,您可以通过覆盖-managedObjectModel手动设置文档的托管对象模型,特别是使用+ mergedModelFromBundles:方法从框架加载模型。根据文档,默认情况下它应该合并主bundle和所有链接框架中的任何模型,因此这只应该是动态加载的bundle所必需的。不知道为什么那不适合你,但我没试过。要找出要搜索的包,NSBundle的+ bundleForClass:方法是你的朋友。

答案 1 :(得分:1)

注意FSExchangeObjects()!它不支持所有卷类型,请参阅bSupportsFSExchangeObjects。我正在寻找替代品。选项似乎是MoreFilesX的FSExchangeObjectsCompat或10.5的FSReplaceObjects()。

答案 2 :(得分:0)

10年后...... 我遇到了同样的问题,使用NSDocument的新API,您可以在执行迁移后使用更新文件的新日期更新文档的fileModificationDate

migrate()
if let newModificationDate = try? NSFileManager.defaultManager().attributesOfItemAtPath(url.path!)[NSFileModificationDate] as? NSDate {
    self.fileModificationDate = newModificationDate
}

之后,您可以拨打super.configurePersistentStoreCoordinatorForURL...

那是因为NSDocument甚至在调用readFromURL:ofType之前就设置了文件修改日期 见Document Initialization Message Flow