Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Core Data Migration: methods in NSEntityMigrationPolicy not called.

I have two model versions - 12 and 13. Then I created a xcmappingmodel-File with source 12 and destination 13.

I subclassed NSEntityMigrationPolicy and added my class to the mappingmodel-File to the entity desired.

@interface EndDateMigrationPolicy : NSEntityMigrationPolicy

enter image description here

After installing and older version (11) on my device, I install the current status with model version 13 - the app runs, but my migration methods aren't called. Am I missing something?

EDIT: is it correct to use these options?

    NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: @YES,
                         NSInferMappingModelAutomaticallyOption: @YES};
like image 695
swalkner Avatar asked Nov 21 '12 12:11

swalkner


2 Answers

I'm going to try to answer you as best I can, I have suffered through core data migrations quite a few times so I know how painful it is. For one you can not hope to have to have your migration work with those options because what you are trying to do is actually not a lightweight migration and yet you are telling it to do a lightweight migration.

Basically let's say you need for some reason to have a non lightweight migration between 2 versions, in your case 11 and 12. What you will need to do is do:

1->12 lightweight 12->13 custom migration 13->(future version) lightweight migration

There might be a better solution but I have not yet found it.

Here is some code to help you out (the hardest parts, I can't remember everything offhand), before this code I copy the database to a backup, so basically the back up database is your old one and the store is your new one (which is empty)

NSString *path = [[NSBundle mainBundle] pathForResource:<YOUR MODEL NAME> ofType:@"cdm"];

NSURL *backUpURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"<YOUR MODEL NAME>MigrationBackUp.sqlite"]; //or whatever you want to call your backup
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"<YOUR MODEL NAME>.sqlite"];
NSError *err2 = nil;
NSDictionary *sourceMetadata2 =
[NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType
                                                           URL:backUpURL
                                                         error:&err2];
NSManagedObjectModel *sourceModel2 = [NSManagedObjectModel mergedModelFromBundles:[NSArray arrayWithObject:[NSBundle mainBundle]]

                                                                 forStoreMetadata:sourceMetadata2];
NSManagedObjectModel *destinationModel2 = [self managedObjectModelForVersion:@"1.4"]; //Yeah your gonna have to get your mapping model , I'll give you this code too later
NSString *oldModel = [[sourceModel2 versionIdentifiers] anyObject];
NSLog(@"Source Model : %@",oldModel);
NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:path]];

if (mappingModel != nil) {
    for (NSString * identifier in [mappingModel entityMappings]) {
        NSLog(@"Mapping > %@",identifier);
    }
}

Then just make a migrator with your source and destination.

This is also a difficult part afterwards:

    BOOL success = [migrator migrateStoreFromURL:backUpURL
                                        type:NSSQLiteStoreType
                                     options:nil
                            withMappingModel:mappingModel
                            toDestinationURL:storeURL
                             destinationType:NSSQLiteStoreType
                          destinationOptions:nil
                                       error:&err2];

Last but not least (I said I'd give it to you before):

- (NSManagedObjectModel *)managedObjectModelForVersion:(NSString*)version {

NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
if (BETWEEN_INEX(version, @"1.0", @"1.4")) {
    modelPath = [modelPath stringByAppendingPathComponent:@"Model"];
    modelPath = [modelPath stringByAppendingPathExtension:@"mom"];
} else if (BETWEEN_INEX(version, @"1.4", @"1.5")) {
    modelPath = [modelPath stringByAppendingPathComponent:@"Model 2"];
    modelPath = [modelPath stringByAppendingPathExtension:@"mom"];
} else if (BETWEEN_INEX(version, @"1.5", @"1.6")) {
    modelPath = [modelPath stringByAppendingPathComponent:@"Model 3"];
    modelPath = [modelPath stringByAppendingPathExtension:@"mom"];
} else if (BETWEEN_INEX(version, @"1.6", @"1.7")) {
    modelPath = [modelPath stringByAppendingPathComponent:@"Model 4"];
    modelPath = [modelPath stringByAppendingPathExtension:@"mom"];
}
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
NSManagedObjectModel * oldManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
NSSet *vIdentifiers = [oldManagedObjectModel versionIdentifiers];
for (NSString * identifier in vIdentifiers) {
    NSLog(@"Old Model : %@",identifier);
}
return [oldManagedObjectModel autorelease];

}

I know these are just snippets of code, but I really hope it helps you solve your problem, if you need anything else just ask.

like image 151
thewormsterror Avatar answered Dec 06 '22 14:12

thewormsterror


Your NSEntityMigrationPolicy is not being called because you set NSInferMappingModelAutomaticallyOption to @(YES) - it should be @(NO)

like image 44
Joseph DeCarlo Avatar answered Dec 06 '22 13:12

Joseph DeCarlo