核心数据迁移映射模型存在问题

发布于 2024-08-12 23:27:19 字数 2835 浏览 5 评论 0原文

我有一个 iPhone 应用程序,它使用 Core Data 进行存储。我已经成功部署了它,现在我正在开发第二个版本。我遇到了数据模型的问题,在持久存储升级时需要进行一些非常简单的数据转换,因此我不能只使用默认的推断映射模型。

我的对象模型存储在 .xcdatamodeld 包中,版本 1.0 和 1.1 彼此相邻。版本 1.1 设置为活动版本。当我使用默认迁移行为并将 NSInferMappingModelAutomaticallyOption 设置为 YES 时,一切正常。我的 sqlite 存储从模型的 1.0 版本升级,一切都很好,当然,除了我需要完成的一些转换。

作为额外的实验步骤,我向核心数据模型包添加了一个新的映射模型,并且没有对 xcode 生成的内容进行任何更改。当我运行我的应用程序(使用旧版本的数据存储)时,我得到以下信息

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Object's persistent store is not reachable from this NSManagedObjectContext's coordinator'

我做错了什么?这是我获取托管对象模型和持久存储协调器的代码。

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

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

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"gti_store.sqlite"]];

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

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
                                                   configuration:nil 
                                                             URL:storeUrl 
                                                         options:options 
                                                           error:&error]) {
        NSLog(@"Eror creating persistent store coodinator - %@", [error localizedDescription]);
    }    

    return _persistentStoreCoordinator;
}


- (NSManagedObjectModel *)managedObjectModel {

    if(_managedObjectModel == nil) {

        _managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
        NSDictionary *entities = [_managedObjectModel entitiesByName];

        //add a sort descriptor to the 'Foo' fetched property so that it can have an ordering - you can't add these from the graphical core data modeler
        NSEntityDescription *entity = [entities objectForKey:@"Foo"];   
        NSFetchedPropertyDescription *fetchedProp = [[entity propertiesByName] objectForKey:@"orderedBar"];
        NSSortDescriptor* sortDescriptor =  [[[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES] autorelease];
        NSArray* sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
        [[fetchedProp fetchRequest] setSortDescriptors:sortDescriptors];
    }
    return _managedObjectModel;
}

I have an iphone app that uses Core Data to do storage. I have successfully deployed it, and now I'm working on the second version. I've run into a problem with the data model that will require a few very simple data transformations at the time that the persistent store gets upgraded, so I can't just use the default inferred mapping model.

My object model is stored in an .xcdatamodeld bundle, with versions 1.0 and 1.1 next to each other. Version 1.1 is set as the active version. Everything works fine when I use the default migration behavior and set NSInferMappingModelAutomaticallyOption to YES. My sqlite storage gets upgraded from the 1.0 version of the model, and everything is good except for, of course, the few transformations I need done.

As an additional experimental step, I added a new Mapping Model to the core data model bundle, and have made no changes to what xcode generated. When I run my app (with an older version of the data store), I get the following

* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Object's persistent store is not reachable from this NSManagedObjectContext's coordinator'

What am I doing wrong? Here's my code for to get the managed object model and the persistent store coordinator.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {

    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

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

    NSURL *storeUrl = [NSURL fileURLWithPath: [[self applicationDocumentsDirectory] stringByAppendingPathComponent: @"gti_store.sqlite"]];

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

    if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType 
                                                   configuration:nil 
                                                             URL:storeUrl 
                                                         options:options 
                                                           error:&error]) {
        NSLog(@"Eror creating persistent store coodinator - %@", [error localizedDescription]);
    }    

    return _persistentStoreCoordinator;
}


- (NSManagedObjectModel *)managedObjectModel {

    if(_managedObjectModel == nil) {

        _managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];    
        NSDictionary *entities = [_managedObjectModel entitiesByName];

        //add a sort descriptor to the 'Foo' fetched property so that it can have an ordering - you can't add these from the graphical core data modeler
        NSEntityDescription *entity = [entities objectForKey:@"Foo"];   
        NSFetchedPropertyDescription *fetchedProp = [[entity propertiesByName] objectForKey:@"orderedBar"];
        NSSortDescriptor* sortDescriptor =  [[[NSSortDescriptor alloc] initWithKey:@"index" ascending:YES] autorelease];
        NSArray* sortDescriptors = [NSArray arrayWithObjects:sortDescriptor, nil];
        [[fetchedProp fetchRequest] setSortDescriptors:sortDescriptors];
    }
    return _managedObjectModel;
}

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

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

发布评论

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

评论(4

向日葵 2024-08-19 23:27:19

我没有仔细考虑过这一点,这只是一个观察,因为我也遇到了同样的问题,而且我在网上也发现很少有关于此错误的参考。

就我而言,问题是我已经设置了应用程序的一个对象来观察

NSManagedObjectContextObjectsDidChangeNotification,如下所示

        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(observeContextSave:)
                                                 name:NSManagedObjectContextDidSaveNotification
                                               object:nil];


- (void) observeContextSave:(NSNotification*) notification {
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];}

一旦我移动了此代码以便在迁移后执行该代码,错误就消失了。

反正。我确信您的情况有所不同。但考虑一下您对来自 ManagedObjectContext 的通知设置了哪些观察可能会有所帮助。

更新:再考虑一下,我猜这是因为在迁移期间创建了多个持久存储,这意味着 NSManagedObjectContextDidSaveNotification 将从具有不同持久存储的上下文发送到发送 mergeChangesFromContextDidSaveNotification 的上下文。

I haven't thought this out very carefully, it's just an observation as I was having the same problem, and I too have found very few references to this error on the web.

In my case the problem was that I had setup one of my application's objects to observe

NSManagedObjectContextObjectsDidChangeNotification like so

        [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(observeContextSave:)
                                                 name:NSManagedObjectContextDidSaveNotification
                                               object:nil];


- (void) observeContextSave:(NSNotification*) notification {
[[self managedObjectContext] mergeChangesFromContextDidSaveNotification:notification];}

Once I moved this code so that is was executed after the migration, the error went away.

Anyway. I'm sure your circumstances are different. But it may help to think about what observations you have setup on notifications from your managedObjectContext.

Update: Having thought about this a bit more, I guess it happens because multiple persistent stores are created during migration, which means that NSManagedObjectContextDidSaveNotification will be sent from a context with a different persistent store to the context that is sent mergeChangesFromContextDidSaveNotification.

清浅ˋ旧时光 2024-08-19 23:27:19

首先,如果您有映射模型,请关闭自动迁移,很可能它们会发生冲突。完成此操作后,请确认错误已消失。

First, turn off the automatic migration if you are having a mapping model, fair chance they are colliding. Once you have done that, confirm that the error is gone.

栩栩如生 2024-08-19 23:27:19

当从辅助线程执行持久存储初始化时,我遇到了类似的问题。在我在主线程中强制初始化后,问题就消失了。诡异的。

I had similar issue when persistent store initialization was performed from secondary thread. After I forced initialization in primary thread the problem has gone. Weird.

樱花细雨 2024-08-19 23:27:19

看来你已经解决了,但值得一提。我也遇到了这个错误,原因是我有多个 MOC 收到 mergeChangesFromContextDidSaveNotification 通知,而它们具有不同的持久存储(或不同的架构)。他们不知道如何处理不属于他们商店的变更。

Seems you already got it fixed, but worth to mention. I had this error too, the reason was I had multiple MOCs being notified of mergeChangesFromContextDidSaveNotification while they had different persistent stores (or different schemas). They didn't know how to handle changes that didn't belong to their stores.

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