核心数据自定义迁移
我的旧核心数据模型有一个NSDate
字段,我想将其更改为NSNumber
。我读苹果文档和SO几个类似的问题和其他博客(见问题的最终参考)核心数据自定义迁移
但无论我做什么,我不断收到同样的错误:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Mismatch between mapping and source/destination models'
我只有该模型的两个版本,并且我已经多次验证源模型和目标模型是正确的。
我甚至放弃了我的所有更改,并重新创建了一个新模型,映射和实体(NSManagedObject
子类)。我一直在这个问题上停留了将近2天,并且不知道我在做什么。任何指针,我做错了将不胜感激。
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (_persistentStoreCoordinator != nil) {
return _persistentStoreCoordinator;
}
NSURL *storeURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"Old.sqlite"];
NSError *error = nil;
_persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSString *sourceStoreType = NSSQLiteStoreType;
NSURL *sourceStoreURL = storeURL;
NSURL *destinationStoreURL = [[self applicationDocumentsDirectory] URLByAppendingPathComponent:@"New.sqlite"];
NSString *destinationStoreType = NSSQLiteStoreType;
NSDictionary *destinationStoreOptions = nil;
NSDictionary *sourceMetadata =
[NSPersistentStoreCoordinator metadataForPersistentStoreOfType:sourceStoreType
URL:sourceStoreURL
error:&error];
if (sourceMetadata == nil) {
NSLog(@"source metadata is nil");
}
NSManagedObjectModel *destinationModel = [_persistentStoreCoordinator managedObjectModel];
BOOL pscCompatibile = [destinationModel
isConfiguration:nil
compatibleWithStoreMetadata:sourceMetadata];
if (pscCompatibile) {
// no need to migrate
NSLog(@"is compatible");
} else {
NSLog(@"is not compatible");
NSManagedObjectModel *sourceModel =
[NSManagedObjectModel mergedModelFromBundles:nil
forStoreMetadata:sourceMetadata];
if (sourceModel != nil) {
NSLog(@"source model is not nil");
NSMigrationManager *migrationManager =
[[NSMigrationManager alloc] initWithSourceModel:sourceModel
destinationModel:destinationModel];
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"MyMigrationMapping" withExtension:@"cdm"];
NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];
NSArray *newEntityMappings = [NSArray arrayWithArray:mappingModel.entityMappings];
for (NSEntityMapping *entityMapping in newEntityMappings) {
entityMapping.entityMigrationPolicyClassName = NSStringFromClass([ConvertDateToNumberTransformationPolicy class]);
}
mappingModel.entityMappings = newEntityMappings;
BOOL ok = [migrationManager migrateStoreFromURL:sourceStoreURL
type:sourceStoreType
options:nil
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:destinationStoreType
destinationOptions:nil
error:&error];
if (ok) {
storeURL = destinationStoreURL;
}
} else {
NSLog(@"e nil source model");
}
}
NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:YES], NSInferMappingModelAutomaticallyOption,
nil];
if (![_persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeURL options:nil error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
abort();
}
return _persistentStoreCoordinator;
}
我定制NSEntityMigration
类:
- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance
entityMapping:(NSEntityMapping *)mapping
manager:(NSMigrationManager *)manager
error:(NSError **)error
{
// Create a new object for the model context
NSManagedObject *newObject =
[NSEntityDescription insertNewObjectForEntityForName:[mapping destinationEntityName]
inManagedObjectContext:[manager destinationContext]];
NSArray *arrayOfKeys = @[@"startDate", @"endDate", @"creationTime", @"timeStamp"];
for (NSString *key in arrayOfKeys) {
// do our transfer of NSDate to NSNumber
NSDate *date = [sInstance valueForKey:key];
NSLog(@"Key: %@, value: %@", key, [date description]);
// set the value for our new object
[newObject setValue:[NSNumber numberWithDouble:[date timeIntervalSince1970]] forKey:key];
}
// do the coupling of old and new
[manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];
return YES;
}
一些参考:
我承认我不明白错误的原因。在我的迁移中,每个实体都有一个策略,我在使用它之前检查实体。不知道这额外if
将帮助您:
- (BOOL)createDestinationInstancesForSourceInstance:(NSManagedObject *)sInstance
entityMapping:(NSEntityMapping *)mapping
manager:(NSMigrationManager *)manager
error:(NSError **)error {
NSEntityDescription *sourceInstanceEntity = [sInstance entity];
if ([[sInstance name] isEqualToString:@"<-name-of-entity>"]) {
newObject = [NSEntityDescription insertNewObjectForEntityForName:@"<-name-of-entity>"
inManagedObjectContext:[manager destinationContext]];
NSArray *arrayOfKeys = @[@"startDate", @"endDate", @"creationTime", @"timeStamp"];
for (NSString *key in arrayOfKeys) {
// do our transfer of NSDate to NSNumber
NSDate *date = [sInstance valueForKey:key];
NSLog(@"Key: %@, value: %@", key, [date description]);
// set the value for our new object
[newObject setValue:[NSNumber numberWithDouble:[date timeIntervalSince1970]] forKey:key];
}
}
// do the coupling of old and new
[manager associateSourceInstance:sInstance withDestinationInstance:newObject forEntityMapping:mapping];
return YES;
}
感谢您试用Olaf。尽管我为我的模式中的每个实体创建了单独的迁移策略,但我仍尝试过您所说的,但仍然无效。 – Neo 2013-05-01 03:18:52
你有没有设法让这个工作? – 2014-06-11 14:47:21
@Neo,你有没有解决这个问题呢? – 2015-03-03 18:59:10
一切你正在做的是方式复杂得多,它必须是。你可以做所有这些,而无需迁移你的数据库。您可以在其他属性添加到您的子类,实现它:
///in your .h
@property(nonatomic, copy) NSNumber* startDateNumber
/// in you .m
-(NSNumber*) startDateNumber{
if (self.startDate) {
return @(self.startDate.timeIntervalSince1970);
}
return nil;
}
-(void)setStartDateNumber:(NSNumber*)startDateNumber{
if(startDateNumber){
self.startDate =[NSDate dateWithTimeIntervalSince1970:startDateNumber.doubleValue];
}else{
self.startDate = nil;
}
}
这是一个有点恼人的有重复的属性(startDate
和startDateNumber
),但它是如此简单得多,并没有任何的迁移问题。
这只是我使用的巨大核心数据模型的一个例子。所以我将不得不找出正确的迁移数据库,使用多通道迁移。 – Nishant 2017-07-10 05:30:05
@Nishant您是否尝试将com.apple.CoreData.MigrationDebug首选项设置为1? – Willeke 2017-07-09 14:44:26
@Willeke是的,我做到了。这并没有明确告诉我为什么这种映射之间的不匹配正在发生。 – Nishant 2017-07-10 05:15:10
从这里很难判断出为什么会出现错误。提出一个新的问题,告诉你改变了什么样的数据模型,你改变了什么默认的映射模型,你在代码中做了什么以及类似的问题。 – Willeke 2017-07-10 05:53:30