Matt
Matt

Reputation: 3652

CoreData custom NSMappingModel not migrating data

I'm trying to manually invoke a CoreData migration using data models created by xcode (.xcdatamodel) and a mapping model created programmatically, at run-time. The migration appears to finish with no errors but the newly created database has no data in it. The structure of the DB is there (tables, Z_METADATA, etc) but the data has not carried over and apparently my NSMappingModel is not being applied.

To summarize the migration: Country entity has been renamed to Country2 and Country.name has been renamed to Country2.new_name.

NSMutableArray *attrMaps = [[NSMutableArray alloc] init];
NSPropertyMapping *pMap = [[NSPropertyMapping alloc] init];
pMap.name = @"new_name";
pMap.valueExpression = [NSExpression expressionForKeyPath:@"source.name"];
[attrMaps addObject:pMap];

NSEntityMapping *eMap = [[NSEntityMapping alloc] init];
eMap.sourceEntityName = @"Country";
eMap.destinationEntityName = @"Country2";
eMap.name = @"CountryToCountry2";
eMap.mappingType = NSTransformEntityMappingType;
eMap.attributeMappings = attrMaps;

NSMutableArray *eMaps = [[NSMutableArray alloc] init];
[eMaps addObject:eMap];

NSMappingModel *mappingModel = [[NSMappingModel alloc] init];
mappingModel.entityMappings = eMaps;

NSURL * storeURL = [NSURL URLWithString:[NSString stringWithFormat:@"file://%@/Documents/%@",NSHomeDirectory(),@"TestCoreData.sqlite"]];
NSURL * storeURL2 = [NSURL URLWithString:[NSString stringWithFormat:@"file://%@/Documents/%@",NSHomeDirectory(),@"TestCoreData2.sqlite"]];
NSMigrationManager *migman = [self getMigrationManager];

NSError * err;
BOOL ok = [migman migrateStoreFromURL:storeURL
                                 type:NSSQLiteStoreType
                              options:nil
                     withMappingModel:mappingModel
                     toDestinationURL:storeURL2
                      destinationType:NSSQLiteStoreType
                   destinationOptions:nil
                                error:&err];

More Info

Comparing my hand-made NSMappingModel to one created in XCode's GUI, you can see a few differences:

From Xcode's GUI

 entityMappings (
"(NSEntityMapping), 
    name CountryToCountry2, 
    mappingType 5, 
    sourceEntityName Country, 
    sourceEntityVersionHash <828c33cf 3ffdc5df dd1e73e8 4f7b60a5 f10dcb43 af26adeb 33d2c518 0c992dd8>, 
    destinationEntityName Country2, 
    destinationEntityVersionHash <8cdb8ecf cb47b39d 4b45858f a247487a dd88088b f509a6ec cc938740 5cf7a041>, attributeMappings (
    "(NSPropertyMapping), name new_name, valueExpression $source.name, userInfo (null)"
    ), relationshipMappings (
), sourceExpression FETCH(FUNCTION($manager, "fetchRequestForSourceEntityNamed:predicateString:" , "Country", "TRUEPREDICATE"), $manager.sourceContext, NO),
   entityMigrationPolicyClassName (null), userInfo (null)"

Mine

entityMappings (
"(NSEntityMapping), 
    name CountryToCountry2, 
    mappingType 5, 
    sourceEntityName Country, 
    sourceEntityVersionHash (null), 
    destinationEntityName Country2, 
    destinationEntityVersionHash (null), 
    attributeMappings (
    "(NSPropertyMapping), name new_name, valueExpression source.name, userInfo (null)",
    ), relationshipMappings (
), sourceExpression (null), 
   entityMigrationPolicyClassName (null), userInfo (null)"

Update

I've added this sourceExpression to my Entity mapping and now the rows of Country are copied over to the new DB but they are empty. So still seems the NSPropertyMappings are not taking effect:

eMap.sourceExpression = [NSExpression expressionWithFormat:@"FETCH(FUNCTION($manager, \"fetchRequestForSourceEntityNamed:predicateString:\" , \"Country\", \"TRUEPREDICATE\"), $manager.sourceContext, NO)"];

Upvotes: 0

Views: 552

Answers (1)

Matt
Matt

Reputation: 3652

The valueExpression for the NSPropertyMapping was defined incorrectly. It should be expressionWithFormat: not expressionForKeyPath: and $source not source. Like this:

pMap.valueExpression = [NSExpression expressionWithFormat:@"$source.name"];

And with that, I have a hand-made NSMappingModel actually working.

Upvotes: 1

Related Questions