无需“文档更改”的手动核心数据模式迁移 警告?

发布于 2024-07-09 20:21:26 字数 3631 浏览 5 评论 0原文

我的基于 Core Data 文档的应用程序(仅限 10.5)的数据模型位于 框架,因此使用核心数据映射自动模式升级 模型似乎不起作用。 看来核心数据机制 当他们找不到合适的数据模型或映射模型时 不在应用程序的主包中。 因此,不要使用自动 迁移,我正在手动运行迁移 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];

The data model for my Core Data document-based app (10.5 only) is in a
framework, so automatic schema upgrades using a Core Data mapping
model don't appear to work. It appears that the Core Data machinery
doesn't find the appropriate data models or mapping model when they
are not in the app's main bundle. So, instead of using the automatic
migration, I'm running a migration manually in
configurePersistentStoreCoordinatorForURL:ofType:... in my
NSPersistenDocument subclass (code below). I migrate the persistent
store to a temporary file and then overwrite the existing file if the
migration succeeds. The document then presents an error with the
message "This document's file has been changed by another application
since you opened or saved it." when I try to save. As others on this
list have pointed out, this is due to my modification of the
document's file "behind its back". I tried updating the document's
file modification date, as shown below, but I then get an error dialog
with the message "The location of the document "test.ovproj" cannot be
determined." when I try to save. I'm less sure of the reason for this
error, but trading one unnecessary message (in this case) for an other
isn't quite what I was going for.

Can anyone offer some guidance? Is there a way to manually upgrade the
schema for a document's persistent store without triggering one of
these (in this case unnecessary) warnings?

code for upgrading the data store in my subclasses
-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];

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

可是我不能没有你 2024-07-16 20:21:26

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

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

I haven't run across this particular situation, but I have a few guesses. First, instead of using -removeItemAtPath: and -moveItemAtPath: when you want to switch files, use the FSExchangeObjects() function instead. NSDocument uses FSRefs to track the file and unless you use FSExchangeObjects(), it'll realize that it's looking at a completely different file.

Second, you can manually set your document's managed object model by overriding -managedObjectModel, in particular using the +mergedModelFromBundles: method to load the models from your framework. According to the docs, it should by default merge any models in the main bundle and in all linked frameworks, so this should only be necessary for dynamically loaded bundles. Don't know why that's not working for you, but I haven't tried this. To figure out what bundles to search, NSBundle's +bundleForClass: method is your friend.

玩心态 2024-07-16 20:21:26

当心 FSExchangeObjects()! 它不支持所有卷类型,请参阅 bSupportsFSExchangeObjects。 我自己也在寻找替代者。 选项似乎是 MoreFilesX 的 FSExchangeObjectsCompat 或 10.5 的 FSReplaceObjects()。

Beware FSExchangeObjects()! It does not support all volumes types, see bSupportsFSExchangeObjects. I'm looking for a replacement myself. Option seem to be MoreFilesX's FSExchangeObjectsCompat or 10.5's FSReplaceObjects().

染柒℉ 2024-07-16 20:21:26

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 之前就设置了文件修改日期
请参阅 文档初始化消息流程

10 years later...
I encountered the same issue, and with the new API for NSDocument, you can update the document's fileModificationDate with the new date of the updated file after doing the migration

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

after that you can call super.configurePersistentStoreCoordinatorForURL...

That's because NSDocument is setting the file modification date even before calling readFromURL:ofType
See Document Initialization Message Flow

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文