2013-12-08 26 views
1

我試圖在插入一些數據後從數據庫中獲取數據時遇到問題。我無法從數據庫中選擇任何行。插入數據庫後無法選擇行

數據庫中有條目,但我無法得到任何結果。

我註釋掉的AppDelegate ::應用這一行:didFinishWithOptions

[dbAccess importWithDelegate:result]; 

,一切工作就好了。但是我找不到解決這個問題的辦法。 我希望你能幫助我。

DatabaseAccess-Class。

#import "KejithDatabaseAccess.h" 
#import "KejithEntryQueryDelegate.h" 

@interface KejithDatabaseAccess(){ 
    sqlite3 *db; 
    NSString *writableDatabase; 
    sqlite3_stmt *statement; 
} 

@end 

@implementation KejithDatabaseAccess 

-(id)init 
{ 
    if((self = [super init])) 
    { 
     // initialize database and store in _db 
    } 

    return self; 
} 

-(void)initializeDatabase 
{ 
    [self createEditableDatabase]; 

    // open the database connection 
    if(sqlite3_open([writableDatabase UTF8String], &db) == SQLITE_OK){ 
     NSLog(@"Database: Connection was opened successfully"); 
    } else { 
     // if something went wrong clean everything up 
     sqlite3_close(db); 
     NSAssert1(0, @"Database: Failed to open database connection. Error: '%s'", sqlite3_errmsg(db)); 
    } 
} 

-(void)closeDatabase 
{ 
    if(sqlite3_close(db) != SQLITE_OK){ 
     NSAssert1(0, @"Database: Failed to close database connection. Error: '%s'", sqlite3_errmsg(db)); 
    } 
} 

-(void)createEditableDatabase 
{ 
    BOOL success; 
    NSError *error; 
    NSFileManager *fileManager = [NSFileManager defaultManager]; 
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDir = [paths objectAtIndex:0]; 

    // create writable database and store path for later use 
    writableDatabase = [documentsDir stringByAppendingPathComponent:@"main-rw.db"]; 

    success = [fileManager fileExistsAtPath: writableDatabase]; 

    // if writable database already exists return 
    if(success) return; 

    // the editable database does not exist 
    // copy the default DB to the application 
    // documents directory 
    NSString *defaultPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"main.db"]; 
    success = [fileManager copyItemAtPath:defaultPath toPath:writableDatabase error:&error]; 

    if(!success){ 
     NSAssert1(0, @"Database: Failed to create writable database file: '%@'.", [error localizedDescription]); 
    } 
} 

-(NSMutableArray *)queryWithDelegate 
{ 

    [self initializeDatabase]; 

    // do we have an delegate? 
    if(![self delegate]) 
     return nil; 

    NSMutableArray *result = [[self delegate] query:db]; 

    [self closeDatabase]; 

    return result; 
} 

-(void)importWithDelegate:(NSMutableArray *)collection 
{ 
    [self initializeDatabase]; 

    [[self delegate] import:collection into:db]; 

    sqlite3_finalize(statement); 

    [self closeDatabase]; 
} 

-(sqlite3 *)getWritableDatabase 
{ 
    return db; 
} 

@end 

數據庫代表級

#import "KejithEntryQueryDelegate.h" 
#import "KejithEntry.h" 

@interface KejithEntryQueryDelegate() 

@property sqlite3 *database; 

@end 

@implementation KejithEntryQueryDelegate 

@synthesize sql; 
@synthesize statement; 

-(id)init 
{ 
    if((self = [super init])){ 
     [self initSQL]; 
    } 

    return self; 
} 

-(void)initSQL 
{ 
    sql = "SELECT _id, entry_title, entry_description, entry_phone, entry_fax, entry_email, entry_website FROM entry"; 
} 

-(NSMutableArray *)query:(sqlite3 *)database 
{ 
    // store database 
    [self setDatabase:database]; 

    // initialize array to store found objects 
    NSMutableArray *entries = [[NSMutableArray alloc] init]; 

    // prepare sql statement 
    int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL); 

    if(sqlResult == SQLITE_OK){ 
     while(sqlite3_step(statement) == SQLITE_ROW){ 
      // allocate object to store row 
      KejithEntry *entry = [[KejithEntry alloc] init]; 

      // get data from columns 
      NSMutableString *title = [NSMutableString stringWithString: 
             [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 1)]]; 

      NSMutableString *description = [NSMutableString stringWithString: 
              [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 2)]]; 

      NSMutableString *phone = [NSMutableString stringWithString: 
             [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 3)]]; 

      NSMutableString *fax = [NSMutableString stringWithString: 
            [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 4)]]; 

      NSMutableString *email = [NSMutableString stringWithString: 
             [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 5)]]; 

      NSMutableString *website = [NSMutableString stringWithString: 
             [NSString stringWithUTF8String:(char *) sqlite3_column_text(statement, 5)]]; 

      // set data in object 
      [entry setId:[NSNumber numberWithInt: sqlite3_column_int(statement, 0)]]; 
      [entry setTitle:title]; 
      [entry setDescription:description]; 
      [entry setPhone:phone]; 
      [entry setFax:fax]; 
      [entry setEmail:email]; 
      [entry setWebsite:website]; 

      // put object into array 
      [entries addObject:entry]; 
     } 

     // finalize the statement to release its resources 
     sqlite3_finalize(statement); 

    } else { 
     // log errors 
     NSLog(@"Database: Problem Occured in KejithEntryQueryDelegate.m"); 
     NSLog(@"Database: Result Code: %d", sqlResult); 
     NSLog(@"Database: SQL-Error: %s", sqlite3_errmsg(database)); 
    } 

    return entries; 
} 

-(void)import:(NSMutableArray *)collection into:(sqlite3 *)database 
{ 
    if([collection count] == 0) 
     return; 

    for(KejithEntry *entry in collection){ 
     [self importEntry:entry into:database]; 
    } 
} 

-(void)importEntry:(KejithEntry *)entry into:(sqlite3 *)database 
{ 
    sql = "INSERT INTO entry (entry_id, entry_title, entry_description, entry_phone, entry_fax, entry_email, entry_website, enty_latitude, entry_longitude, entry_category_id) \ 
      VALUES \ 
      (0,?,?,?,?,?,?,0,0,0);"; 

    int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL); 
    sqlite3_bind_text(statement, 1, [[entry title] UTF8String], -1, SQLITE_STATIC); 
    sqlite3_bind_text(statement, 2, [[entry getDescription] UTF8String], -1, SQLITE_STATIC); 
    sqlite3_bind_text(statement, 3, [[entry phone] UTF8String], -1, SQLITE_STATIC); 
    sqlite3_bind_text(statement, 4, [[entry fax] UTF8String], -1, SQLITE_STATIC); 
    sqlite3_bind_text(statement, 5, [[entry email] UTF8String], -1, SQLITE_STATIC); 
    sqlite3_bind_text(statement, 6, [[entry website] UTF8String], -1, SQLITE_STATIC); 

    if(sqlite3_step(statement) != SQLITE_DONE){ 
     NSLog(@">> Database: Failed to insert into Database"); 
     NSLog(@"SQL Error Message: %s", sqlite3_errmsg(database)); 
    } 

    sqlite3_finalize(statement); 
} 

@end 

的AppDelegate ::應用:didFinishWithLaunchingOptions

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 
{ 
    self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 
    // Override point for customization after application launch. 
    self.window.backgroundColor = [UIColor whiteColor]; 
    [self.window makeKeyAndVisible]; 

    // create delegate for entry xml parsing 
    id delegate = [[KejithEntryXmlDelegate alloc] init]; 

    KejithXmlParser *parser = [[KejithXmlParser alloc] initWithUrl:[[NSURL alloc] initWithString:entryXmlUrl]]; 
    KejithDatabaseAccess *dbAccess = [[KejithDatabaseAccess alloc] init]; 
    KejithEntryQueryDelegate *dbEntryDelegate = [[KejithEntryQueryDelegate alloc] init]; 

    // set delegate to parse xml file 
    [parser setDelegate:delegate]; 
    // set delegate to query data to/from database 
    [dbAccess setDelegate:dbEntryDelegate]; 

    // get results of xml parsing 
    NSMutableArray *result = [parser parse]; 
    NSLog(@"Count of ParseResult: %d", [result count]); 

    [dbAccess importWithDelegate:result]; 
    NSLog(@"Count of DatabaseResult: %d", [[dbAccess queryWithDelegate] count]); 

    return YES; 
} 

控制檯 - 輸出而不[DBACCESS importWithDelegate:結果]註釋:

2013-12-08 15:59:44.035 staedteApp[30202:70b] Database: Connection was opened successfully 
2013-12-08 15:59:44.048 staedteApp[30202:70b] Database: Connection was opened successfully 
2013-12-08 15:59:44.049 staedteApp[30202:70b] Count of DatabaseResult: 0 

控制檯-輸出與[DBACCESS importWithDelegate:結果]註釋:

2013-12-08 16:17:18.084 staedteApp[30267:70b] Database: Connection was opened successfully 
2013-12-08 16:17:18.091 staedteApp[30267:70b] Count of DatabaseResult: 50 

EDIT#1 ----- 更新KejithEntryQueryDelegate :: importEntry:進

-(void)importEntry:(KejithEntry *)entry into:(sqlite3 *)database 
{ 
    sql = "INSERT INTO entry (entry_id, entry_title, entry_description, entry_phone, entry_fax, entry_email, entry_website, enty_latitude, entry_longitude, entry_category_id) \ 
      VALUES \ 
      (0,?,?,?,?,?,?,0,0,0);"; 

    int sqlResult = sqlite3_prepare_v2(database, sql, -1, &statement, NULL); 
    if(sqlResult != SQLITE_DONE){ 
     sqlite3_bind_text(statement, 1, [[entry title] UTF8String], -1, SQLITE_STATIC); 
     sqlite3_bind_text(statement, 2, [[entry getDescription] UTF8String], -1, SQLITE_STATIC); 
     sqlite3_bind_text(statement, 3, [[entry phone] UTF8String], -1, SQLITE_STATIC); 
     sqlite3_bind_text(statement, 4, [[entry fax] UTF8String], -1, SQLITE_STATIC); 
     sqlite3_bind_text(statement, 5, [[entry email] UTF8String], -1, SQLITE_STATIC); 
     sqlite3_bind_text(statement, 6, [[entry website] UTF8String], -1, SQLITE_STATIC); 


     int sqlStepResult; 
     if((sqlStepResult = sqlite3_step(statement)) != SQLITE_DONE){ 
      NSLog(@">> Database: Failed to insert into Database"); 
      NSLog(@"SQL Error Message: %s", sqlite3_errmsg(database)); 
      NSLog(@"SQL Step Result: %d", sqlStepResult); 
     } 
    } else { 
     NSLog(@"Database: Problem Occured in KejithEntryQueryDelegate.m step"); 
     NSLog(@"Database: Result Code: %d", sqlResult); 
     NSLog(@"Database: SQL-Error: %s", sqlite3_errmsg(database)); 
    } 

    sqlite3_finalize(statement); 
} 

回答

0

的問題是您使用的實例變量爲sql,在創建KejithEntryQueryDelegate時將其設置爲SELECT語句,將其更改爲importEntry:into:方法中的INSERT語句,但當您調用query:,儘管代碼明確假定它應該是SELECT聲明,但sql仍然是INSERT聲明。

通過查看sqlite3_step(下面第3點)的結果代碼,可以快速確定問題。由於sqlResult != DONE,你想記錄問題,它報告「entry.entry_title可能不是NULL」(這在SELECT聲明中沒有意義,這使我意識到舊的INSERT聲明仍在sql變量中)。

我的原始答案,基於一瞥代碼如下。點#3是關鍵的觀察。


只看代碼,我沒有看到任何明顯會導致您描述的行爲。如果我正確地按照你的意思,你說如果你做不是導入數據,找到50條記錄,但是如果你試圖導入數據,你不僅看不到新數據,而且突然沒有什麼是找到(包括已經存在的記錄)。那真的是你說的嗎?這是好奇的行爲。如果這實際上是這個問題,那麼這會導致我懷疑導入嘗試導致隨後的嘗試讀取失敗。

這裏唯一明顯的SQLite問題是importWithDelegate不應該調用sqlite3_finalize。我甚至不明白爲什麼KejithDatabaseAccess有一個sqlite3_stmt,因爲你沒有準備那個班的任何陳述。也許打電話sqlite3_finalize與一些無效sqlite3_stmt導致問題?

這裏有一些小的事情:

  1. importEntry:into:應該大概檢查sqlite3_prepare_v2語句的結果。在其他地方,你確認準備工作在繼續之前成功了,但不在這裏。

  2. query方法是將電子郵件地址存儲到網站屬性。

  3. 我還保存sqlite3_step結果在query方法,讓你可以檢查錯誤,例如:

    while((sqlResult = sqlite3_step(statement)) == SQLITE_ROW) { 
        // do all of your updating of entries here 
    } 
    if (sqlResult != SQLITE_DONE) { 
        NSLog(@"Database: Problem Occured in KejithEntryQueryDelegate.m step"); 
        NSLog(@"Database: Result Code: %d", sqlResult); 
        NSLog(@"Database: SQL-Error: %s", sqlite3_errmsg(database)); 
    } 
    

    現在,如果你sqlite3_step方法失敗,你永遠不會知道。

+0

嗨,羅布,感謝您的回答。首先:對,就是那種好奇的行爲。我試過你提到的一切。我編輯了我的帖子「編輯#1」。控制檯輸出仍然相同。你提到的最終版本只是一個隨機的嘗試,但在我的問題之後被刪除。 – kejith

+0

@kejith在那個修改過的SQL中,準備好後,你有'if(sqlResult!= SQLITE_DONE)...',我想你的意思是'if(sqlResult == SQLITE_OK)...'。 'SQLITE_DONE'只是來自step函數的響應。但是抱歉,更廣泛的問題並沒有在我身上跳躍。如果您在某處(例如github,dropbox)上傳項目,我很高興看一看。 – Rob

+0

感謝您的幫助。請耐心等待。這是我第一次用iOS和Objective C進行開發。我刪除了我以前的評論。 – kejith