Custom code execution after light weight migration of particular version
Asked Answered
U

6

12

I have 2 object models in Core Data (say v1 and v2). This migration is eligible for light weight migration. Now, I want to execute custom code after the migration but only when the migration is from v1 to v2. Later on if I introduce v3, I don't want the custom code to get executed.

Is there a way to do this?

Thanks in advance, Anupam

Undergraduate answered 29/6, 2011 at 20:10 Comment(2)
Can someone please help me out?Undergraduate
Last time I was wanting to do something like this I ended up just going with a custom migration... but often the bulk of a migration could be lightweight if only that final custom step could be included so I like the question. Bounty added to this question to draw some further attention and see if anyone has a good answer to this.Confounded
G
10

Here is how to handle this situation, basically by using the store's metadata, as suggested by Apple engineers at WWDC 2010:

  • Open the store (with migration options)
  • Check metadata for custom key, e.g. “DonePostProcessing”
  • Do post-processing...
    • Populate derived attributes
    • Insert or delete objects
    • Set store metadata (“DonePostProcessing” = YES)
  • Save changes and metadata

More or less, something like



- (void)loadStoreWithMigration:(NSURL *)url {
    ...

   store = [psc addPersistentStoreWithType: NSSQLiteStoreType configuration: nil URL: url options: opts error: &err];

   m = [store metadata];
   key = @”DonePostProcessing”;
   if (m && ([[m objectForKey: key] integerValue] < 2) ){
      [self doPostProcessingInContext: context];
      m2 = [[m mutableCopy] autorelease];
      [m2 setObject: [NSNumber numberWithInteger: 2] forKey: key];
      [store setMetadata: m2];

      ok = [context save:&err];
   }

}
Genisia answered 14/11, 2011 at 22:38 Comment(1)
This is such a perfect solution for me, as I have a calculated field that needs to be updated whenever I change the algorithm. Thanks!Cuccuckold
E
1

There might be a better way, buy this should work:

Keep track of the DB version by keeping an entity in Core Data named "Information" and have a property named "CoreDataVersion".

After the migration code finishes add code to check for the version number in the core data.

If the value of "CoreDataVersion" is "v1" and your app is now at "v2" (this can be hardcoded with each version), execute the additional custom code and then write the new version back to the DB.

If you already have "v1" published to users, just say that if there is no "CoreDataVersion" in the DB, then it is "v1".

Eloyelreath answered 8/11, 2011 at 17:26 Comment(0)
F
1
- (void) _performMaintanaceUpdate:(NSUInteger) newVersion oldVersion:(NSUInteger) oldVersion {
            if (newVersion>=1020500 && oldVersion < 1020500) {
                NSString *storePath = [[PreferenceDataModel getDataPath] stringByAppendingPathComponent: @"wcal.sqlite"];
                NSFileManager *fileManager = [NSFileManager defaultManager];
                if ([fileManager fileExistsAtPath:storePath]) {
                        [fileManager removeItemAtPath:storePath error:NULL];
                }
                [PreferenceDataModel setVersionOfLastMaintanace:newVersion]; 
            }
}

 (void) _checkAndPerformMaintenance{
    NSString* strVersion = [PreferenceDataModel getApplicationVersion];
    //legal version is xx.xx.xx where x is a dec digit 1.2 or 1.2.33 is legit 
    NSUInteger ver = 0;
    NSUInteger finalVer = 0;
    int t = 3; 

    for (int i=0; i<[strVersion length]; i++) {
        char c = [strVersion characterAtIndex:i];
        if (isdigit(c)) {
            ver*=10;
            ver+=c - 48;
        }
        else {
            finalVer+= ver * pow(100, t--); 
            ver = 0;
        }
    }
    finalVer+= ver * pow(100, t);
    [self _performMaintanaceUpdate:finalVer oldVersion:[PreferenceDataModel getVersionOfLastMaintanace]];
}

and this is how you retrieve apps version

+(NSString *) getApplicationVersion {
    return [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"];
}
Fantasia answered 8/11, 2011 at 23:13 Comment(0)
F
1

Before you create the persistent store that does the automatic migration, determine if you'll be migrating to version 2. If you will be, set a flag to do your changes after the migration happens.

To determine what you'll be migrating from, do this:

NSString *path = [[NSBundle mainBundle] pathForResource:@"Model" ofType:@"momd"];
NSURL *momURL = [NSURL fileURLWithPath:path];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:momURL];
NSString *version = [managedObjectModel.versionIdentifiers anyObject];

The version identifiers are set in Xcode.

Ferrate answered 10/11, 2011 at 19:46 Comment(0)
F
1

Another way to do it is to do a custom data migration from v1 to v2. Start by looking over http://www.timisted.net/blog/archive/core-data-migration/.

Ferrate answered 10/11, 2011 at 19:50 Comment(0)
H
0

Another solution that worked well for me:

    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
    NSInteger currVersion = [defaults integerForKey:@"dataModelVersion"];
    NSString *version = [managedObjectModel.versionIdentifiers anyObject];
    if (currVersion == 0) {
        [defaults setInteger:[version integerValue] forKey:@"dataModelVersion"];
    }
    else if (currVersion < [version integerValue]) {
        NSLog(@"Migration Code");
        [defaults setInteger:[version integerValue] forKey:@"dataModelVersion"];
    }
Hildagarde answered 19/5, 2014 at 7:20 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.