核心数据:用于打开商店的模型与用于创建商店的模型不兼容

时间:2016-05-19 12:23:41

标签: ios objective-c core-data

我的应用包含2个数据库:

  • db1:读/写数据库(用于存储所有用户设置)
  • db2:一个只读数据库,预装在另一个项目中(我复制了.sqlite,.xcdatamodeld和项目中的实体类)

如果我使用2 MOC和2 PSC(每个数据库一个)初始化Core Data:一切正常。但是我想为这两个数据库初始化只有1个MOC / PSC。为此,我编写了以下代码:

- (NSManagedObjectContext *)managedObjectContext
{
    if (_managedObjectContext != nil) {
        return _managedObjectContext;
    }

    NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
    if (coordinator != nil) {
        _managedObjectContext = [[NSManagedObjectContext alloc] init];
        [_managedObjectContext setPersistentStoreCoordinator:coordinator];
    }
    return _managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel
{
    if (_managedObjectModel != nil) {
        return _managedObjectModel;
    }
    NSURL *db1ModelURL = [[NSBundle mainBundle] URLForResource:@"db1" withExtension:@"momd"];
    NSManagedObjectModel *db1Mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:db1ModelURL];
    NSURL *db2ModelURL = [[NSBundle mainBundle] URLForResource:@"db2" withExtension:@"momd"];
    NSManagedObjectModel *db2Mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:db2ModelURL];
    NSAssert(db1 != nil, @"Error initializing Managed Object Model");
    NSAssert(db2 != nil, @"Error initializing Managed Object Model");

    _managedObjectModel=[NSManagedObjectModel modelByMergingModels:[NSArray db1Mom,db2Mom, nil]];

    return _managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator
{
    if (_persistentStoreCoordinator != nil) {
        return _persistentStoreCoordinator;
    }

    NSURL * db1URL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"db1.sqlite"];

    NSURL *db2URL = [[NSBundle mainBundle] URLForResource:@"db2" withExtension:@"sqlite"];

    NSError *error = nil;
    _persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];

    _persistentStoreCoordinator = [[self managedObjectContext] persistentStoreCoordinator];
    NSMutableDictionary * db2Options=[NSMutableDictionary dictionaryWithObjectsAndKeys:
                                         @YES,NSReadOnlyPersistentStoreOption,
                                         nil];
    NSPersistentStore *store = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"DB2" URL:db2URL options:db2Options error:&error];
    NSAssert(store != nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);

    NSMutableDictionary * db1Options=[NSMutableDictionary dictionaryWithObjectsAndKeys:
                                         @YES,NSMigratePersistentStoresAutomaticallyOption,
                                         @YES,NSInferMappingModelAutomaticallyOption,
                                         nil];
    store = [_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:@"DB1" URL:db1URL options:db1Options error:&error];
    NSAssert(store != nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);

    return _persistentStoreCoordinator;
}

当我启动应用程序时,我在DB2数据库上收到以下错误:

The model used to open the store is incompatible with the one used to create the store

我认为问题来自对modelByMergingModels的调用,结果模型包含db2Model,但Core Data不会将其识别为此数据库的基本模型...

连连呢?

2 个答案:

答案 0 :(得分:0)

这种情况正在发生,因为您最初使用其中一个数据库在手机中安装了该应用。现在您已添加/更改了数据库。所以它无法识别新的数据库。因为应用程序最初是使用不同的数据库创建/安装的。

尝试从手机中删除该应用并重新安装。错误将会发生。

希望这会有所帮助。 :)

答案 1 :(得分:0)

我找到了解决这个article的解决方案。即使我不明白它为什么会起作用......

- (void)initializeCoreData{
// Initialize models
NSURL *db2ModelURL = [[NSBundle mainBundle] URLForResource:@"villes" withExtension:@"momd"];
NSManagedObjectModel *db2Mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:db2ModelURL];
NSAssert(db2Mom != nil, @"Error initializing Managed Object Model");

NSURL *db1ModelURL = [[NSBundle mainBundle] URLForResource:@"MMAMeteoPro" withExtension:@"momd"];
NSManagedObjectModel *db1Mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:db1ModelURL];
NSAssert(db1Mom != nil, @"Error initializing Managed Object Model");


NSManagedObjectModel * fullModel=[NSManagedObjectModel modelByMergingModels:[NSArray arrayWithObjects:db1Mom,db2Mom, nil]];

// Initialize context
NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:fullModel];
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
[moc setPersistentStoreCoordinator:psc];
[self setManagedObjectContext:moc];

// Initialize stores
NSURL *db2StoreURL = [[NSBundle mainBundle] URLForResource:@"db2" withExtension:@"sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentsURL = [[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *db1StoreURL = [documentsURL URLByAppendingPathComponent:@"db1.sqlite"];

dispatch_async(dispatch_get_global_queue( DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    NSError *error = nil;
    NSPersistentStoreCoordinator *psc = [[self managedObjectContext] persistentStoreCoordinator];
    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             [NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
                             [NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
                             nil];
    NSMutableDictionary * db2Options=[NSMutableDictionary dictionaryWithObjectsAndKeys:
                                   @{@"journal_mode":@"DELETE"},NSSQLitePragmasOption,
                                   @YES, NSReadOnlyPersistentStoreOption,
                                   nil];
    NSMutableDictionary * db1Options=[NSMutableDictionary dictionaryWithObjectsAndKeys:
                                         @{@"journal_mode":@"DELETE"},NSSQLitePragmasOption,
                                         nil];
    NSPersistentStore * tempStore = [psc addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:db2StoreURL options:options error:&error];
    NSAssert(error == nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
    [psc removePersistentStore:tempStore error:&error];
    NSAssert(error == nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
    tempStore=[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"DB2Conf" URL:villeStoreURL options:db2Options error:&error];
    NSAssert(error == nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
    tempStore=[psc addPersistentStoreWithType:NSSQLiteStoreType configuration:@"DB1Conf" URL:meteoStoreURL options:db1Options error:&error];
    NSAssert(error == nil, @"Error initializing PSC: %@\n%@", [error localizedDescription], [error userInfo]);
});

}

我们必须:

  1. 首先添加ReadOnly持久性存储,并启用轻量级迁移选项,并且没有ReadOnly选项或配置
  2. 删除此持久存储(???)
  3. 再次添加它,这次没有轻量级迁移选项,但使用了ReadOnly和良好的配置。
  4. 添加读/写持久存储
  5. 如果有人能解释我为什么这个配置有效...因为我真的不明白这一点。