Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom code execution after light weight migration of particular version

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

like image 257
Anupam Godbole Avatar asked Jun 29 '11 20:06

Anupam Godbole


People also ask

What is lightweight migration?

Core Data can typically perform an automatic data migration, referred to as lightweight migration. Lightweight migration infers the migration from the differences between the source and the destination managed object models.

What is heavy weight migration?

We perform heavyweight migration when we have either normalized or generalized our database. In such cases, lightweight migration won't help us. We will have to manually map attributes of the old data model to the new data model, and doing so is called heavyweight migration.

How do I migrate to core data?

Migrations happen in three steps: First, Core Data copies over all the objects from one data store to the next. Next, Core Data connects and relates all the objects according to the relationship mapping. Finally, enforce any data validations in the destination model.


3 Answers

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];
   }

}
like image 146
Massimo Cafaro Avatar answered Oct 22 '22 09:10

Massimo Cafaro


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".

like image 35
Tal Bereznitskey Avatar answered Oct 22 '22 10:10

Tal Bereznitskey


- (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"];
}
like image 20
bioffe Avatar answered Oct 22 '22 09:10

bioffe