2013-04-25 35 views
9

Mô hình dữ liệu cốt lõi cũ của tôi có trường NSDate, mà tôi muốn thay đổi thành NSNumber. Tôi đọc tài liệu của Apple và một số câu hỏi tương tự trên SO và các blog khác (xem tài liệu tham khảo ở cuối của câu hỏi)Di chuyển tùy chỉnh dữ liệu chính

Nhưng không có vấn đề gì tôi làm, tôi tiếp tục nhận được lỗi tương tự:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Mismatch between mapping and source/destination models'

tôi chỉ có 2 phiên bản của mô hình, và tôi đã xác minh thời gian và một lần nữa rằng các mô hình nguồn và đích là chính xác.

Tôi thậm chí đã bỏ tất cả các thay đổi của mình và tạo lại một mô hình, ánh xạ và thực thể mới (NSManagedObject các lớp con). Tôi đã bị mắc kẹt này trong gần 2 ngày nay, và không còn manh mối nào nữa về những gì tôi đang làm. Bất kỳ gợi ý về những gì tôi đang làm sai sẽ được đánh giá cao.

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

tùy chỉnh của tôi NSEntityMigration lớp:


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

Một số tài liệu tham khảo:

  1. Example or explanation of Core Data Migration with multiple passes?
  2. Core Data - Default Migration (Manual)
  3. http://www.preenandprune.com/cocoamondo/?p=468
  4. http://www.timisted.net/blog/archive/core-data-migration/
+0

@Nishant Bạn đã thử đặt tùy chọn com.apple.CoreData.MigrationDebug thành 1? – Willeke

+0

@Willeke Vâng, tôi đã làm điều đó. Điều đó không rõ ràng cho tôi biết tại sao sự không khớp này giữa các ánh xạ đang xảy ra. – Nishant

+0

Rất khó để kể từ đây tại sao bạn gặp lỗi. Đặt một câu hỏi mới và cho biết những gì bạn đã thay đổi thành mô hình dữ liệu, những gì bạn đã thay đổi thành mô hình ánh xạ mặc định, những gì bạn đã làm trong mã và vấn đề tương tự là gì. – Willeke

Trả lời

1

Tôi thừa nhận tôi không hiểu nguyên nhân của lỗi. Trong quá trình di chuyển của tôi, tôi có một chính sách cho mỗi pháp nhân và tôi đang kiểm tra thực thể trước khi sử dụng nó. Không chắc chắn nếu thêm if này sẽ giúp bạn:

- (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; 

}

+0

Cảm ơn bạn vì đã cố gắng Olaf. Tôi đã thử những gì bạn nói, và nó vẫn không hoạt động, mặc dù tôi đã tạo ra các chính sách di trú riêng lẻ cho mọi thực thể trong lược đồ của tôi. – Neo

+0

Bạn có quản lý để làm việc này không? –

+0

@Neo, bạn đã sửa lỗi này chưa? –

1

Tất cả những gì bạn đang làm là cách phức tạp hơn nó phải được. Bạn có thể làm tất cả những điều này mà không cần di chuyển cơ sở dữ liệu của bạn cả. Bạn có thể thêm tài sản khác để phân lớp của bạn mà thực hiện nó:

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

Nó là một chút khó chịu là có tính trùng lặp (startDatestartDateNumber) nhưng nó là như vậy đơn giản hơn nhiều và không có bất kỳ vấn đề di cư.

+0

Đây chỉ là một ví dụ về mô hình dữ liệu cốt lõi hoành tráng mà tôi đang sử dụng. Vì vậy, tôi sẽ phải tìm ra cách di chuyển cơ sở dữ liệu đúng cách, sử dụng di chuyển nhiều lần. – Nishant

Các vấn đề liên quan