我有以下代码,它基于youtube上的教程实现,但我更改了一些以满足我的目的,即插入硬编码的项目..数据库已创建,而且表格但我发现addItems没有添加。 我不认为addItemToTable方法有问题, 我认为在这里列出的第一部分是一个逻辑错误,但找不到它。任何帮助都会很棒
提前致谢
这些是项目:
table_ok = YES;
if (table_ok) {
if (!db_open_status) {
[self openDBWithSQLName:dataBaseName];
NSLog(@"DB opened");
}
NSMutableDictionary *objectColsVals = [[NSMutableDictionary alloc]init];
NSString *this_id = @"12";
NSString *this_name = @"and";
NSString *this_email = @"123@hotmail.com";
NSString *this_password = @"aa11111";
NSString *this_role = @"Marketing";
[objectColsVals setValue:this_id forKey:[my_columns_names objectAtIndex:0]];
[objectColsVals setValue:this_name forKey:[my_columns_names objectAtIndex:1]];
[objectColsVals setValue:this_email forKey:[my_columns_names objectAtIndex:2]];
[objectColsVals setValue:this_password forKey:[my_columns_names objectAtIndex:3]];
[objectColsVals setValue:this_role forKey:[my_columns_names objectAtIndex:4]];
if ([[objectColsVals allKeys] count] > 0) {
if ([self addItemToTable:tableName WithColumnValues:objectColsVals]) {
NSLog(@"inserted");
[self closeDB];
}
}
这个方法:
-(BOOL)addItemToTable:(NSString *)usetable WithColumnValues:(NSDictionary *)valueObject{
BOOL has_beenAdded = NO;
NSString *mycolumns = @"";
NSString *myvalues = @"";
//loop through all the value keys
for (int r=0; r<[[valueObject allKeys] count]; r++) {
NSString *this_keyname = [[valueObject allKeys]objectAtIndex:r];
mycolumns = [mycolumns stringByAppendingString:this_keyname];
NSString *thisval = [NSString stringWithFormat:@"'%@'",[valueObject objectForKey:this_keyname]];
myvalues = [myvalues stringByAppendingString:thisval];
//add commas to seperate the col and val lists before last item
if (r<(([[valueObject allKeys] count])-1)) {
mycolumns = [mycolumns stringByAppendingString:@","];
myvalues = [myvalues stringByAppendingString:@","];
}
}
NSString *myinsert = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES(%@)",usetable,mycolumns,myvalues];
char *err;
if (sqlite3_exec(estate_db, [myinsert UTF8String], NULL, NULL, &err) != SQLITE_OK) {
sqlite3_close(estate_db);
}else{
has_beenAdded = YES;
}
return has_beenAdded;
}
答案 0 :(得分:1)
就你所拥有的而言,很难说问题出在哪里。似乎没有什么是错的。应该至少应该:
检查以编程方式生成的INSERT
语句的内容,以确保没有一些微妙的问题无法粗略检查代码;
如果任何sqlite3_xxx()
调用失败(特别是如果sqlite3_exec
返回除SQLITE_OK
之外的任何内容),则记录错误消息(err
变量,或者通过致电sqlite3_errmsg()
);如果你不看这些错误信息,你只是盲目飞行;以及
在模拟器上运行应用程序,然后在Mac上打开模拟器的数据库副本(在~/Library/Application Support/iPhone Simulator
目录中;如果隐藏了~/Library
文件夹,请通过运行在终端命令行工具中使用chflags -nohidden ~/Library
命令)并直接检查数据库的内容。验证列名,表名等。
同样,目前还不清楚问题出在哪里,但它很可能只是在打开数据库或创建相关表格时会出现一些混乱。在我们确认错误消息和实际SQL之前,很难说。它可以是尝试打开捆绑包中数据库的只读副本,错误地调用sqlite3_open
并无意中创建新的空白数据库。您真的应该更新问题并共享创建数据库的代码(或从包中复制它),以及执行上面概述的一些诊断步骤。
说完这些之后,我真的不鼓励你用stringWithFormat
将值添加到SQL中。 SQL的动态构建很好,但你真的不应该使用stringWithFormat
将值插入SQL本身。鉴于您使用单引号引用文本值,如果该人的姓氏为O'Brian
,该怎么办?或者,如果您更改了例程以使用双引号,那么该人的名字是Dwayne "The Rock" Johnson
怎么办?如果字符串定界符出现在数据值中,则当前代码可能会失败。更糟糕的是,你在技术上暴露自己的SQL注入攻击。
您通常应该使用?
占位符。例如,考虑如下定义的字典:
NSDictionary *dataToInsert = @{@"name" : @"Jack",
@"id" : @37,
@"password" : @"feefifofum",
@"role" : [NSNull null],
@"email" : @"jack@magicbeans.fairyland.com",
@"hourly_wage" : @12.85};
您要做的是构建一个如下所示的SQL语句:
INSERT INTO test (name,id,password,role,email,hourly_wage) VALUES (?,?,?,?,?,?)
然后,您希望使用?
函数将值绑定到这些sqlite3_bind_xxx()
占位符。
因此,您可以创建和准备SQL语句(构建values
数组和placeholders
数组),如下所示:
NSArray *keys = [dataToInsert allKeys];
NSMutableArray *values = [NSMutableArray arrayWithCapacity:[keys count]];
NSMutableArray *placeholders = [NSMutableArray arrayWithCapacity:[keys count]];
// build array of values and array of question mark placeholders
for (NSString *key in keys) {
[values addObject:[dataToInsert objectForKey:key]];
[placeholders addObject:@"?"];
}
// use the `keys` and `placeholders` arrays to build the SQL
NSString *insertSql = [NSString stringWithFormat:@"INSERT INTO %@ (%@) VALUES (%@)",
tableName,
[keys componentsJoinedByString:@","],
[placeholders componentsJoinedByString:@","]];
if (sqlite3_prepare_v2(db, [insertSql UTF8String], -1, &statement, NULL) != SQLITE_OK) {
NSLog(@"prepare failed: %s", sqlite3_errmsg(db));
sqlite3_close(db);
return;
}
// statement is prepared, but we still have to bind the values...
然后,您可以使用以下内容绑定值。这是动态检查values
数组中对象的类(如果它是NSNumber
,请查看objCType
以确定数字的类型):
// now use the `values` array to bind values to the ? placeholders
[values enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
int rc = SQLITE_ERROR;
if ([obj isKindOfClass:[NSString class]])
rc = sqlite3_bind_text(statement, idx + 1, [obj UTF8String], -1, SQLITE_TRANSIENT);
else if ([obj isKindOfClass:[NSNull class]])
rc = sqlite3_bind_null(statement, idx + 1);
else if ([obj isKindOfClass:[NSNumber class]]) {
const char *objCType = [obj objCType];
if (strcmp(objCType, @encode(int)) == 0 || strcmp(objCType, @encode(unsigned int)) == 0 || strcmp(objCType, @encode(short)) == 0 || strcmp(objCType, @encode(unsigned short)) == 0 || strcmp(objCType, @encode(char)) == 0 || strcmp(objCType, @encode(unsigned char)) == 0)
rc = sqlite3_bind_int(statement, idx + 1, [obj integerValue]);
else if (strcmp(objCType, @encode(long)) == 0 || strcmp(objCType, @encode(unsigned long)) == 0 || strcmp(objCType, @encode(long long)) == 0 || strcmp(objCType, @encode(unsigned long long)) == 0)
rc = sqlite3_bind_int64(statement, idx + 1, [obj longLongValue]);
else if (strcmp(objCType, @encode(float)) == 0 || strcmp(objCType, @encode(double)) == 0)
rc = sqlite3_bind_double(statement, idx + 1, [obj doubleValue]);
else {
NSLog(@"column %d is %@ but has unknown numeric type %s; will use `description`", idx + 1, obj, objCType);
rc = sqlite3_bind_text(statement, idx + 1, [[obj description] UTF8String], -1, SQLITE_TRANSIENT);
}
}
else
rc = sqlite3_bind_text(statement, idx + 1, [[obj description] UTF8String], -1, SQLITE_TRANSIENT);
if (rc != SQLITE_OK)
{
NSLog(@"bind %d failed: %s", idx + 1, sqlite3_errmsg(db));
sqlite3_finalize(statement);
sqlite3_close(db);
return;
}
}];
if (sqlite3_step(statement) != SQLITE_DONE) {
NSLog(@"step failed: %s", sqlite3_errmsg(db));
sqlite3_close(db);
return;
}
sqlite3_finalize(statement);