2013-09-24 40 views
1

我有一個SQLite數據庫爲我的應用程序。從db中檢索實體我使用這種方法:objective-c sqlite3數據庫更改不持久

- (sqlite3*) openDatabaseNamed:(NSString*)databaseName 
{ 
    if(![databaseName isEqualToString:kTopInternationalDatabaseName] && 
     ![databaseName isEqualToString:kTop500RODatabaseName]){ 
     NSAssert(nil, @"Database does not exist!"); 
    } 
    sqlite3 * dataBase; 
    NSString * path; 
    path = [[NSBundle mainBundle] pathForResource:databaseName ofType:@"sqlite3"]; 
    if (sqlite3_open([path UTF8String], &dataBase) != SQLITE_OK) { 
     NSString * errorString = [NSString stringWithFormat:@"[SQLITE] Unable to open database <%@> ",databaseName]; 
     NSAssert(nil,errorString); 
    } 
    return dataBase; 
} 

- (NSArray *) getAllEntitiesForDatabaseNamed:(NSString*)databaseName 
{ 
    (...) 
    sqlite3 * database = [self openDatabaseNamed:databaseName]; 

    NSMutableArray *retval = [[NSMutableArray alloc] init]; 
    NSString *query = [NSString stringWithFormat:@"SELECT * FROM %@",databaseName]; 

    NSArray *properties = [entityClass classProperties]; 

    if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) 
     == SQLITE_OK) { 
     while (sqlite3_step(statement) == SQLITE_ROW) { 


      for (int i=2; i<countLimit; i++){ 

       chars = (char *) sqlite3_column_text(statement,i+1); 
       if(chars != NULL) 
       { 
        containerString = [NSString stringWithUTF8String:chars]; 
        if(containerString && containerString.length>0){ 
         [entityModel setValue:containerString forKey:properties[i]]; 
        } 
       } 
      } 
      [retval addObject:entityModel]; 
     } 
     sqlite3_finalize(statement); 
    } 
    sqlite3_close(database); 
    return retval.copy; 
} 

一切都按預期工作。爲了將實體的自定義字段設置爲數據庫中的特定值,我使用此方法:

- (void)setEntity:(EntityModel *)entity favorite:(BOOL)favorite 
{ 
    NSString *query = [NSString stringWithFormat:@"UPDATE %@ SET favorite = %i WHERE position = '%i';",kDatabaseName,favorite?1:0,entity.positionInTop]; 

    sqlite3_stmt *statement; 
    sqlite3 * database = [self openDatabaseNamed:kTop500RODatabaseName]; 

    if (sqlite3_prepare_v2(database, [query UTF8String], -1, &statement, nil) 
     == SQLITE_OK) { 
     sqlite3_step(statement); 
     sqlite3_finalize(statement); 
    } 
    sqlite3_close(database); 
} 

發生的事情有點奇怪。如果我使用更新方法並且在使用getAllEntitiesForDatabaseNamed的所有實體的應用查詢的同一生命週期中,我對setEntity:Favorite:所做的更改仍然存在。另一方面,如果我使用更新方法,然後關閉應用程序並重新啓動它,則使用setEntity:Favorite:所做的更改將丟失。任何想法是爲什麼?

PS:我也用sqlite3_exec試過,仍然結果是相同的:

if (sqlite3_exec(database, [query UTF8String], NULL, NULL, NULL) != SQLITE_OK) { 
    // deal with error... 
    NSLog(@" -- ERROR!"); 
} 

回答

4

的問題是,你的包,這是隻讀打開數據庫(一個設備上,在最小)。相反,您應該檢查數據庫是否存在於您的文檔文件夾中,如果不存在,請從數據包中將其複製,然後從「文檔」文件夾中打開數據庫。

因此,你可以這樣做:

NSString *bundlePath = [[NSBundle mainBundle] pathForResource:databaseName ofType:@"sqlite"]; 

NSString *documentsFolder = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0]; 
NSString *documentsPath = [[documentsFolder stringByAppendingPathComponent:databaseName] stringByAppendingPathExtension:@"sqlite"]; 

NSFileManager *fileManager = [NSFileManager defaultManager]; 

if (![fileManager fileExistsAtPath:documentsPath]) { 
    NSError *error = nil; 
    BOOL success = [fileManager copyItemAtPath:bundlePath toPath:documentsPath error:&error]; 
    NSAssert(success, @"%s: copyItemAtPath failed: %@", __FUNCTION__, error); 
} 

已經這樣做了,你現在可以繼續在documentsPath打開數據庫。

+0

你能再詳細一點嗎? – Teo

+0

@Theo。查看代碼示例。 – Rob

+0

我相信雖然斷言是錯誤的,並且它會在複製成功時使應用程序崩潰。 – Teo