No suitable mapping model found for core data migration

前端 未结 5 1707
走了就别回头了
走了就别回头了 2020-12-29 12:15

I\'m trying to perform an iOS Core Data migration that requires a MappingModel. Core data is not able to use the mapping model for some reason and it falls back to an automa

5条回答
  •  一整个雨季
    2020-12-29 12:37

    After futher investigation I found out I was experiencing the same issue as mentioned here (Core Data migration fails for to-one relationship). Settings the minimum to 1 instead of no minimum in my relationship made Core Data use my custom mapping model. While I'm not sure I assume this is a bug in Core Data.
    However, this required me to change the original (1.0) mapping model (which users were already using) too. The fix I came up with is to create a new mapping model between 1.0 and 2.0 called 1.5. The only thing that's different in 1.5 in comparison with 1.0 is the minimum of the relationship, which is in 1.5 set to 1. Now, I could let Core Data perform a lightweight migration from 1.0 to 1.5 and hereafter perform my own custom migration from 1.5 to 2.0. Although it may be a hacky solution, it works perfectly. I pasted the code that handles the migration below.

    - (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
        if (persistentStoreCoordinator != nil) {
            return persistentStoreCoordinator;
        }
    
        NSURL *storeUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Project.sqlite"]];
        NSError *error;
    
        NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeUrl error:&error];
    
        if (! [[self managedObjectModel] isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) {
            // The current store isn't compatible with the model and should be migrated, check the version identifier of the store
    
            NSManagedObjectModel *sourceManagedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:storeMetadata];
    
            if ([[sourceManagedObjectModel versionIdentifiers] containsObject:@"Model_1_0"]) {
                // The current version of the store is 1.0, a manual migration to 1.5 is needed in order to migrate finally to 2.0
    
                NSURL *destinationModelURL = [[NSBundle mainBundle] URLForResource:@"Model.momd/Model_1_5" withExtension:@"mom"];
                NSManagedObjectModel *destinationManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:destinationModelURL];
    
                NSMigrationManager *migrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceManagedObjectModel destinationModel:destinationManagedObjectModel];
                NSMappingModel *inferredMappingModel = [NSMappingModel inferredMappingModelForSourceModel:sourceManagedObjectModel destinationModel:destinationManagedObjectModel error:&error];
    
                NSURL *destinationURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Migration.sqlite"]];
    
                [migrationManager migrateStoreFromURL:storeUrl
                                                 type:NSSQLiteStoreType
                                              options:nil
                                     withMappingModel:inferredMappingModel
                                     toDestinationURL:destinationURL
                                      destinationType:NSSQLiteStoreType
                                   destinationOptions:nil
                                                error:&error];
                if (error) {
                    DLog(@"Failed to migrate store from URL %@ with mapping model %@ to destination URL %@ with error %@", storeUrl, inferredMappingModel, destinationURL, error);
                }
    
                [[NSFileManager defaultManager] removeItemAtURL:storeUrl error:&error];
                [[NSFileManager defaultManager] moveItemAtURL:destinationURL toURL:storeUrl error:&error];
            }
        }
    
        NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: [NSNumber numberWithBool:YES],
                                  NSInferMappingModelAutomaticallyOption: [NSNumber numberWithBool:NO] };
        persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
    
        if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) {
            /*Error for store creation should be handled in here*/
            DLog(@"%@", error);
        }
    
        return persistentStoreCoordinator;
    }
    

提交回复
热议问题