[英]Standard core data migration with multiple passes not working
我在這里遵循了有關核心數據標准遷移的教程:
http://mipostel.com/index.php/home/70-core-data-migration-standard-migration-part-2
然后在這里進行多次通過:
這給了我這里的結果代碼:
- (NSManagedObjectContext *)managedObjectContext {
if (managedObjectContext != nil) {
return managedObjectContext;
}
NSPersistentStoreCoordinator *coordinator = [self persistentStoreCoordinator];
if (coordinator != nil) {
managedObjectContext = [TICDSSynchronizedManagedObjectContext new];
[managedObjectContext setPersistentStoreCoordinator: coordinator];
}
return managedObjectContext;
}
- (NSManagedObjectModel *)managedObjectModel {
if (managedObjectModel != nil) {
return managedObjectModel;
}
// managedObjectModel = [[NSManagedObjectModel mergedModelFromBundles:nil] retain];
NSString *modelPath = [[NSBundle mainBundle] pathForResource:@"EntryDatabase" ofType:@"momd"];
NSURL *modelURL = [NSURL fileURLWithPath:modelPath];
managedObjectModel = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL];
return managedObjectModel;
}
- (NSPersistentStoreCoordinator *)persistentStoreCoordinator {
if (persistentStoreCoordinator != nil) {
return persistentStoreCoordinator;
}
NSString *storePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStore.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
// If the expected store doesn't exist, copy the default store.
NSLog(@"file exists at path: %@, %i", storePath, [fileManager fileExistsAtPath:storePath]);
if (![fileManager fileExistsAtPath:storePath]) {
NSString *defaultStorePath = [[NSBundle mainBundle] pathForResource:@"CoreDataStore" ofType:@"sqlite"];
if (defaultStorePath) {
[fileManager copyItemAtPath:defaultStorePath toPath:storePath error:NULL];
}
}
persistentStoreCoordinator = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:[self managedObjectModel]];
NSURL *storeUrl = [NSURL fileURLWithPath:storePath];
NSError *error;
NSDictionary *pscOptions = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:YES], NSMigratePersistentStoresAutomaticallyOption,
[NSNumber numberWithBool:NO], NSInferMappingModelAutomaticallyOption,
nil];
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:pscOptions
error:&error]) {
NSLog(@"Unresolved error %@, %@", error, [error userInfo]);
}
return persistentStoreCoordinator;
}
- (BOOL)checkForMigration
{
BOOL migrationSuccess = NO;
NSString *storeSourcePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStoreNew.sqlite"];
NSFileManager *fileManager = [NSFileManager defaultManager];
if (![fileManager fileExistsAtPath:storeSourcePath]) {
//Version 2 SQL has not been created yet, so the source is still version 1...
storeSourcePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStore.sqlite"];
}
NSURL *storeSourceUrl = [NSURL fileURLWithPath: storeSourcePath];
NSError *error = nil;
NSDictionary *sourceMetadata = [NSPersistentStoreCoordinator
metadataForPersistentStoreOfType:NSSQLiteStoreType
URL:storeSourceUrl
error:&error];
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) ?@"YES" :@"NO");
if (pscCompatible == NO) {
migrationSuccess = [self performMigrationWithSourceMetadata:sourceMetadata toDestinationModel:destinationModel];
}
}
else {
NSLog(@"checkForMigration FAIL - No Source Metadata! \nERROR: %@", [error localizedDescription]);
}
return migrationSuccess;
}
- (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];
NSArray *mappingModelNames = [NSArray arrayWithObjects:@"StepOne", @"StepTwo", nil];
NSDictionary *sourceStoreOptions = nil;
NSString *destinationStorePath = [[self applicationDocumentsDirectory]
stringByAppendingPathComponent:@"CoreDataStoreNew.sqlite"];
NSURL *destinationStoreURL = [NSURL fileURLWithPath: destinationStorePath];
NSString *destinationStoreType = NSSQLiteStoreType;
NSDictionary *destinationStoreOptions = nil;
for (NSString *mappingModelName in mappingModelNames) {
NSError *error;
NSURL *fileURL = [[NSBundle mainBundle] URLForResource:mappingModelName withExtension:@"cdm"];
NSMappingModel *mappingModel = [[NSMappingModel alloc] initWithContentsOfURL:fileURL];
migrationSuccess = [standardMigrationManager migrateStoreFromURL:destinationStoreURL
type:NSSQLiteStoreType
options:sourceStoreOptions
withMappingModel:mappingModel
toDestinationURL:destinationStoreURL
destinationType:destinationStoreType
destinationOptions:destinationStoreOptions
error:&error];
NSLog(@"Error: %@", error);
}
}
return migrationSuccess;
}
盡管如此,該應用程序內存不足,並在persistentStoreCoordinator
中的行崩潰:
if (![persistentStoreCoordinator addPersistentStoreWithType:NSSQLiteStoreType
configuration:nil
URL:storeUrl
options:pscOptions
error:&error]) {
我記得也曾聽過本教程。
實際上,我發現這不是正確的方法。 順便說一句,您是否閱讀了該教程的最后評論並嘗試刪除提到的內容? 也許這可以解決您的問題?
無論如何,我意識到(遵循本教程之后,修改無濟於事)有一種簡單得多的方法。
對於您的情況,我不知道,如果這個小的修改不能解決問題,我真的會尋找另一個參考-因為這確實不是正確的方法,並且會引導您走錯方向,因為它試圖做到一切本身,而不是像我發現的困難方式那樣使用Apple核心數據遷移過程背后的邏輯。
幾年前,我解決的問題是從一個存儲庫中取出一個子樹,然后將其復制到另一個存儲庫中,我所做的工作應該對您有用。 我在Mac上執行此操作,因此內存不是問題,但是根據Core Data Programming Guide“減少內存開銷”,通過適當的故障處理和減少內存,您應該能夠使它起作用。
以下解決方案是基於MOM並沒有那么大的差異而提出的。 讓我為現有上下文引入術語“ A”,為新上下文引入術語“ B”。
1)第一步是復制B中A中的每個對象。如果類保持不變,則很好。 這意味着對於每個對象,您需要一個來自實體的所有值的列表。 我建議使用鍵-每個實體類型的屬性鍵的數組,這將使編碼(如果可以)更加容易。 否則,您實際上可以從MOM中獲取密鑰-這就是我在舊代碼中所做的事情。
現在關鍵的步驟-您必須創建翻譯詞典(也許您需要兩個-我做了),對於A中的每個實體,您都知道'B'中的對應實體。 您可以使用'objectID'屬性(但對於B而言,請不要保存直到保存此值更改后再保存)。
2)現在您已經完全重新創建了所有實體,您需要將它們“連接”起來-以便正確設置所有關系。 再次,為每種實體類型創建一些鍵數組,然后在循環中查看“ A”中的每個關系,獲取其指向的實體,使用轉換表在“ B”中找到對應的實體,然后設置“ B”中的值。
瞧! 完成。 您顯然是在進行添加以反映從A到B的更改,因此添加的內容就是刪除的內容。
同樣,我不需要擔心Mac上的內存,因此也不需要技巧來降低內存。 我相信錯誤('refreshObject:mergeChanges:')會為您提供幫助,但再也不必這樣做(即使如此,可能只是大尺寸的對象)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.