插入数据库后无法选择行

时间:2013-12-08 15:20:08

标签: iphone database select insert sqlite

我在插入一些数据后尝试从数据库中获取数据时出现问题。我无法从数据库中选择任何行。

数据库中有条目,但我无法获得任何结果。

我在AppDelegate :: application:didFinishWithOptions

中注释掉这一行
[dbAccess importWithDelegate:result];

一切正常。但我无法找到解决这个问题的方法。 我希望你能帮助我。

DatabaseAccess级。

#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

Database Delegate-Class

#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:result]的控制台输出已注释掉:

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:result]注释掉的控制台输出:

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

编辑#1 ----- 更新了KejithEntryQueryDelegate :: importEntry:into

-(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);
}

1 个答案:

答案 0 :(得分:0)

问题是您正在为sql使用实例变量,在创建SELECT时将其设置为KejithEntryQueryDelegate语句,并将其更改为INSERT语句在importEntry:into:方法中,但是当您调用query:时,即使代码明确假定它应该是SELECT语句,sql仍然是INSERT语句。

通过查看sqlite3_step的结果代码(下面的第3点),可以快速识别问题。从sqlResult != DONE开始,您想要记录问题并报告“entry.entry_title可能不是NULL”(这在SELECT语句中没有意义,这让我意识到旧的INSERT 1}}语句仍然在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方法失败,您将永远不会知道。