9

私の古いコア データ モデルにはNSDateフィールドがあり、これを に変更したいと考えていNSNumberます。Appleのドキュメントと、SOおよび他のブログでいくつかの同様の質問を読みました(質問の最後の参照を参照してください)

しかし、私が何をしても、同じエラーが発生し続けます:

キャッチされない例外 'NSInvalidArgumentException' によるアプリの終了、理由: 'マッピングとソース/宛先モデル間の不一致'

モデルのバージョンは 2 つしかありませんが、ソース モデルとターゲット モデルが正しいことを何度も確認しました。

すべての変更を破棄し、新しいモデル、マッピング、およびエンティティ (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;
}

参考文献:

  1. 複数のパスを使用した Core Data Migration の例または説明は?
  2. コア データ - デフォルトの移行 (手動)
  3. http://www.preenandprune.com/cocoamondo/?p=468
  4. http://www.timisted.net/blog/archive/core-data-migration/
4

2 に答える 2

1

エラーの原因がわからないことを認めます。私の移行では、エンティティごとに 1 つのポリシーがあり、使用する前にエンティティをチェックしています。この追加機能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;

}

于 2013-04-28T11:32:20.983 に答える