2012-11-29 95 views
2

我有一個當前正在使用的應用程序。我對這個應用的核心數據模型的下一個版本做了重大修改。生產應用程序中的iOS核心數據對象模型更改

爲了避免從舊數據模型到新數據模型的大量轉換工作,我簡單地重新命名了新的對象模型和數據庫,從而導致新版本的應用程序不再引用舊數據庫(這是不是一個問題,因爲舊的數據庫數據很小,而且不需要)。

然而,我確實需要從舊數據庫中獲取一份數據,但我不希望用戶需要手動將其重新輸入到新數據庫中。

我的問題: 我有什麼方法可以將這段數據存入新數據庫?

我可以對sqlite數據庫運行查詢,只需進入新的數據庫?或者我是否需要創建一個完整的其他持久性存儲&對象模型來提取數據?

還是我錯過了所有的東西?

回答

0

感謝上述兩個建議。最後我用以下解決我的問題:

步驟:

  • 嘗試連接到舊SQLite數據庫。
  • 如果連接成功,請閱讀該記錄。
  • 在託管對象上下文中創建一個新的託管對象。
  • 使用sql結果中的值填充託管對象中的值。
  • 堅持託管對象。
  • 刪除舊數據庫。
 
NSString *dbFilePath = [[self applicationDocumentsDirectoryString] stringByAppendingPathComponent:@"RPS.sqlite"]; 

sqlite3 *database; 

if (sqlite3_open([dbFilePath UTF8String], &database)) { 
    NSLog(@"sqlite3_open: failed"); 
} else { 
    NSString *nsquery = [[NSString alloc] initWithFormat:@"SELECT * FROM ztable"]; 
    const char *query = [nsquery UTF8String]; 

    sqlite3_stmt *statement; 
    int prepareCode = (sqlite3_prepare_v2(database, query, -1, &statement, NULL)); 
    if(prepareCode == SQLITE_OK) { 
     MyTable *myTableRecord; 
     NSLog(@"About to start adding the data"); 
     while (sqlite3_step(statement) == SQLITE_ROW) 
     { 
      NSLog(@"***************** row returned ******************"); 

      myObject = [NSEntityDescription insertNewObjectForEntityForName:@"myTable" inManagedObjectContext:self.managedObjectContext]; 

      [myTable setValue:[NSString stringWithFormat:@"%s",(char *)sqlite3_column_text(statement, 7)] forKey:@"field1"]; 
      [myTable setValue:[NSString stringWithFormat:@"%s",(char *)sqlite3_column_text(statement, 8)] forKey:@"field2"]; 

      [self saveContext]; 

     } 

     sqlite3_finalize(statement); 
     NSLog(@"Added sqlite3 data"); 
    } else { 
     NSLog(@"Prepare code was not right: %d",prepareCode); 
    } 

    NSError *err; 
    NSFileManager *filemgr = [[NSFileManager alloc] init]; 
    [filemgr removeItemAtPath:dbFilePath error:&err]; 
    NSLog(@"Deleted old sqlite3 database"); 
} 
+0

這是一個漂亮的解決方案。我假設你沒有嘗試進行原地CoreData遷移,因爲你的模型變化很嚴重?當然,對於「簡單」的模型更改,自動遷移是要走的路... –

+0

準確地說..自動遷移並未涵蓋我所做的所有關係變更等。這可能有點hacky ..但它很簡單:)。 – mtb

+0

簡單的作品。 :-)有一種方法可以編寫「真正」的遷移,而不是自動遷移,並隱藏所有隱藏的東西(如SQLite數據庫)。但是,這可能是「真正的」工作以獲得正確的結果。 :-) –

1

您似乎只需要將數據複製到用戶第一次運行更新應用程序的新數據庫中。那時你可能會清理掉舊的,所以它佔用了空間。不確定需要多少複雜的解決方案。似乎足夠。

+0

我猜我想知道的最好/最簡單的方法來做到這一點。我寧願沒有2個對象模型的等...只是這一次操作。 – mtb

1

我同意,我認爲你應該使用核心數據連接到舊數據庫並將數據提取出來,然後將其移至新數據庫。大功告成之後,你應該像這樣刪除舊的數據庫文件(注:我假設你存儲的核心數據結果到SQLite的):

- (NSURL *)urlForDocumentsDirectoryWithFile:(NSString *)fileName { 
    NSURL *docPath = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject]; 
    return [docPath URLByAppendingPathComponent:fileName]; 
} 

- (void)deleteFileFromDocumentsIfExists:(NSString *)fileName { 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSError *error; 
    NSURL *filePath = [self urlForDocumentsDirectoryWithFile:fileName]; 
    NSLog(@"Deleting file: %@", filePath.absoluteString); 
    if ([fileManager fileExistsAtPath:[filePath path]]) 
    { 
     BOOL success = [fileManager removeItemAtURL:filePath error:&error]; 
     if (!success) NSLog(@"Error: %@", [error localizedDescription]); 
    } 
} 

刪除代碼:

[self deleteFileFromDocumentsIfExists:@"MyOldDatabaseName.sqlite"]; 

如果你只有一次曾經使用舊的,我不會擔心有兩種對象模型。我可以看到在應用程序中使用「曾經使用過」代碼是浪費,但即使跳過核心數據並手動查詢仍然需要您擁有此代碼。

此外,我有一個DataAccessManager單元,可以將所有核心數據的荒謬初始化代碼轉儲到所以它使得我可以輕鬆訪問多個上下文,如果您擔心的是您正在手動編寫所有內容將其轉移到一個可共享的單位。

相關問題