2013-02-26 15 views
9

Sto tentando di eseguire una migrazione di dati di base iOS che richiede un MappingModel. I dati principali non sono in grado di utilizzare il modello di mappatura per qualche motivo e ricadono in una migrazione leggera automatica.Nessun modello di mappatura adatto trovato per la migrazione dei dati di base

Ho abilitato l'opzione MigrationDebug per ottenere maggiori informazioni e quello che vedo non ha senso. Gli hash di origine e di destinazione del modello di mappatura sono identici, ignorando l'ordine, ai ManagedObjectModels di origine e destinazione. Sembra che debba essere usato il modello di mappatura ma il log dice "non è stato trovato alcun modello di mappatura adatto".

Ecco la (eliso) log:

CoreData: annotation: (migration) will attempt automatic schema migration 
CoreData: annotation: (migration) looking for mapping model with 
source hashes: 
{ 
    TSBaseEntity = <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>; 
    TSBuyer = <91e837d1 3f348913 eff634d6 6fb9b3a6 747e2390 fbdc4ae6 32cc56d6 7582d4a8>; 
    ... 
} 
destination hashes: { 
    TSBaseEntity = <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>; 
    TSBuyer = <e316a857 8919c4be eef15387 5c67a21b 67d32919 99ead438 1ff93c05 2e065fcc>; 
    ... 
} 
CoreData: annotation: (migration) checking mapping model at path file://localhost/Users/xandrews/Library/Application%20Support/iPhone%20Simulator/6.1/Applications/0A84951E-21FC-47C0-A1B7-F880ACB672C4/Dev.app/Migrate_0_5_24To_0_5_27.cdm 
source hashes: 
{(
    <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>, 
    <91e837d1 3f348913 eff634d6 6fb9b3a6 747e2390 fbdc4ae6 32cc56d6 7582d4a8>, 
    ... 
)} 
destination hashes: {(
    <4797118c 50068f2f f544d9a9 4884720b 55ec7e4d 0d4c8f4e 1ee44be3 b06d2edc>, 
    <e316a857 8919c4be eef15387 5c67a21b 67d32919 99ead438 1ff93c05 2e065fcc>, 
    ... 
)} 
CoreData: annotation: (migration) no suitable mapping model found 
CoreData: annotation: (migration) inferring a mapping model between data models with 
source hashes: ... 

risposta

8

Il modello di mappatura generato da Xcode 4 non produce gli hash corretti necessari per la migrazione. È possibile confrontare l'uscita dal registro della migrazione al hash del file di mapping con il codice qui sotto:

NSString *mappingModelPath = [[NSBundle mainBundle] pathForResource:@"MappingFile" ofType:@"cdm"]; 
    NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:[NSURL fileURLWithPath:mappingModelPath]]; 

    for (NSEntityMapping *entityMapping in mappingModel.entityMappings) { 
     NSLog(@"%@: %@", entityMapping.sourceEntityName, entityMapping.sourceEntityVersionHash); 
     NSLog(@"%@: %@", entityMapping.destinationEntityName, entityMapping.destinationEntityVersionHash); 
    } 

Vedrete che questi non corrispondono gli hash nell'output registro di migrazione.

La soluzione è quello di generare il file di mapping in Xcode 5.

+0

Quindi non possiamo usare lo strumento di migrazione in Xcode 4.6.2, perché genera il file sbagliato ?? –

+2

Non so se questa sia la soluzione, ma sicuramente è una soluzione. L'utilizzo del file generato da Xcode 5 DP4 ha funzionato per me. –

+1

Per Xcode 4, provare [questa risposta] (http://stackoverflow.com/a/9428260/1402846). – Pang

0

Il modello di mappatura non è probabilmente sufficiente per gestire la migrazione. In questo caso il modello di mappatura non verrà caricato, anche se corrisponde al modello di origine e di destinazione.

Scrivere un test per la migrazione. Ripristina le modifiche al tuo modello passo dopo passo e prova la migrazione. In questo modo troverai la modifica che impedisce il caricamento del modello di mappatura.

Ricerca: Rinominare gli attributi o creare attributi senza specificare i valori predefiniti. Modifica degli attributi a non facoltativo.

In questi casi è necessario specificare il comportamento manualmente all'interno del modello di mappatura.

+0

Sto avendo lo stesso problema e anche se ho già riscritto il modello di mappatura da zero non sono ancora in grado di farlo funzionare. La migrazione non riesce, non importa quello che cerco. – s1m0n

0

Aveva lo stesso problema. Ho cancellato un'entità e ribattezzato i campi della relazione di conseguenza. Per prima cosa ho provato a utilizzare la migrazione leggera e quindi gli ID di rinomina specificati per le relazioni. A causa di una svista ho confuso i campi usati per "Renaming ID" e "Hash Modifier". Una volta corretto, tutto funziona come previsto.

3

nel metodo persistentStoreCoordinator dare questa riga di codice

NSDictionary *options=[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption,[NSNumber numberWithBool:YES],NSInferMappingModelAutomaticallyOption, nil]; 

Se questo non aiuta, allora avete bisogno di andare per l'utente implementata la migrazione. Quindi dovrai creare un modello di mappatura usando il modello di origine e di destinazione. In questo caso insieme,

NSDictionary *options=[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],NSMigratePersistentStoresAutomaticallyOption,[NSNumber numberWithBool:NO],NSInferMappingModelAutomaticallyOption, nil]; 

Crea metadati douce con seguente codice

if (sourceMetadata) { 
     NSString *configuration = nil; 
     NSManagedObjectModel *destinationModel = [self.persistentStoreCoordinator managedObjectModel]; 

     //Our Source 1 is going to be incompatible with the Version 2 Model, our Source 2 won't be... 
     BOOL pscCompatible = [destinationModel isConfiguration:configuration compatibleWithStoreMetadata:sourceMetadata]; 
     NSLog(@"Is the STORE data COMPATIBLE? %@", (pscCompatible==YES) [email protected]"YES" :@"NO"); 

     if (pscCompatible == NO) { 
      migrationSuccess = [self performMigrationWithSourceMetadata:sourceMetadata toDestinationModel:destinationModel]; 
     } 
    } 
    else { 
     NSLog(@"checkForMigration FAIL - No Source Metadata! \nERROR: %@", [error localizedDescription]); 
    } 

e implementare la seguente funzione

- (BOOL)performMigrationWithSourceMetadata :(NSDictionary *)sourceMetadata toDestinationModel:(NSManagedObjectModel *)destinationModel 
{ 
    BOOL migrationSuccess = NO; 
    //Initialise a Migration Manager... 
    NSManagedObjectModel *sourceModel = [NSManagedObjectModel mergedModelFromBundles:nil 
                    forStoreMetadata:sourceMetadata]; 
    //Perform the migration... 
    if (sourceModel) { 
     NSMigrationManager *standardMigrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceModel 
                         destinationModel:destinationModel]; 
     //Retrieve the appropriate mapping model... 
     NSMappingModel *mappingModel = [NSMappingModel mappingModelFromBundles:nil 
                   forSourceModel:sourceModel 
                   destinationModel:destinationModel]; 
     if (mappingModel) { 
      NSError *error = nil; 
      NSString *storeSourcePath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Recipes.sqlite"]; 
      NSURL *storeSourceUrl = [NSURL fileURLWithPath: storeSourcePath]; 
      NSString *storeDestPath = [[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Recipes2.sqlite"]; 
      NSURL *storeDestUrl = [NSURL fileURLWithPath:storeDestPath]; 

      //Pass nil here because we don't want to use any of these options: 
      //NSIgnorePersistentStoreVersioningOption, NSMigratePersistentStoresAutomaticallyOption, or NSInferMappingModelAutomaticallyOption 
      NSDictionary *sourceStoreOptions = nil; 
      NSDictionary *destinationStoreOptions = nil; 

      migrationSuccess = [standardMigrationManager migrateStoreFromURL:storeSourceUrl 
                     type:NSSQLiteStoreType 
                    options:sourceStoreOptions 
                  withMappingModel:mappingModel 
                  toDestinationURL:storeDestUrl 
                  destinationType:NSSQLiteStoreType 
                  destinationOptions:destinationStoreOptions 
                     error:&error]; 
      NSLog(@"MIGRATION SUCCESSFUL? %@", (migrationSuccess==YES)[email protected]"YES":@"NO"); 
     } 
    } 
    else { 
     //TODO: Error to user... 
     NSLog(@"checkForMigration FAIL - No Mapping Model found!"); 
     abort(); 
    } 
    return migrationSuccess; 
} 
1

Dopo indagini futher ho scoperto che stavo vivendo lo stesso problema come menzionato qui (Core Data migration fails for to-one relationship). Imposta il minimo su 1 anziché il minimo nella mia relazione. I dati principali utilizzano il mio modello di mappatura personalizzato. Anche se non sono sicuro, presumo che si tratti di un bug in Core Data.
Tuttavia, questo mi ha richiesto di cambiare il modello di mappatura originale (1.0) (che già usavano gli utenti). La correzione che mi è venuta in mente è di creare un nuovo modello di mappatura tra 1.0 e 2.0 chiamato 1.5. L'unica cosa diversa in 1.5 rispetto a 1.0 è il minimo della relazione, che è in 1.5 impostato su 1. Ora, potrei permettere a Core Data di eseguire una migrazione leggera da 1.0 a 1.5 e di seguito eseguire la mia migrazione personalizzata da 1.5 a 2.0. Sebbene possa essere una soluzione hacky, funziona perfettamente.Ho incollato il codice che gestisce la migrazione di seguito.

- (NSPersistentStoreCoordinator *)persistentStoreCoordinator { 
    if (persistentStoreCoordinator != nil) { 
     return persistentStoreCoordinator; 
    } 

    NSURL *storeUrl = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Project.sqlite"]]; 
    NSError *error; 

    NSDictionary *storeMetadata = [NSPersistentStoreCoordinator metadataForPersistentStoreOfType:NSSQLiteStoreType URL:storeUrl error:&error]; 

    if (! [[self managedObjectModel] isConfiguration:nil compatibleWithStoreMetadata:storeMetadata]) { 
     // The current store isn't compatible with the model and should be migrated, check the version identifier of the store 

     NSManagedObjectModel *sourceManagedObjectModel = [NSManagedObjectModel mergedModelFromBundles:nil forStoreMetadata:storeMetadata]; 

     if ([[sourceManagedObjectModel versionIdentifiers] containsObject:@"Model_1_0"]) { 
      // The current version of the store is 1.0, a manual migration to 1.5 is needed in order to migrate finally to 2.0 

      NSURL *destinationModelURL = [[NSBundle mainBundle] URLForResource:@"Model.momd/Model_1_5" withExtension:@"mom"]; 
      NSManagedObjectModel *destinationManagedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:destinationModelURL]; 

      NSMigrationManager *migrationManager = [[NSMigrationManager alloc] initWithSourceModel:sourceManagedObjectModel destinationModel:destinationManagedObjectModel]; 
      NSMappingModel *inferredMappingModel = [NSMappingModel inferredMappingModelForSourceModel:sourceManagedObjectModel destinationModel:destinationManagedObjectModel error:&error]; 

      NSURL *destinationURL = [NSURL fileURLWithPath:[[self applicationDocumentsDirectory] stringByAppendingPathComponent:@"Migration.sqlite"]]; 

      [migrationManager migrateStoreFromURL:storeUrl 
              type:NSSQLiteStoreType 
              options:nil 
           withMappingModel:inferredMappingModel 
           toDestinationURL:destinationURL 
            destinationType:NSSQLiteStoreType 
           destinationOptions:nil 
              error:&error]; 
      if (error) { 
       DLog(@"Failed to migrate store from URL %@ with mapping model %@ to destination URL %@ with error %@", storeUrl, inferredMappingModel, destinationURL, error); 
      } 

      [[NSFileManager defaultManager] removeItemAtURL:storeUrl error:&error]; 
      [[NSFileManager defaultManager] moveItemAtURL:destinationURL toURL:storeUrl error:&error]; 
     } 
    } 

    NSDictionary *options = @{NSMigratePersistentStoresAutomaticallyOption: [NSNumber numberWithBool:YES], 
           NSInferMappingModelAutomaticallyOption: [NSNumber numberWithBool:NO] }; 
    persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]]; 

    if(![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType configuration:nil URL:storeUrl options:options error:&error]) { 
     /*Error for store creation should be handled in here*/ 
     DLog(@"%@", error); 
    } 

    return persistentStoreCoordinator; 
} 
Problemi correlati