自Android中的SQLite开始以来,这个问题困扰着我。选择参数为Strings
。什么?为什么呢?
我们来看看我的问题。我有一个正确填充的数据库:
sqlite> select count (*) from issues where project_id = 1;
3819
大。我们来看看代码:
public Cursor selectAllCursor(final long projectId) {
final String selection = projectId > 0 ? KEY_PROJECT + " = ?" : null;
final String[] selArgs = projectId > 0 ? new String[] {
Long.toString(projectId)
} : null;
final Cursor c = mDb.query(TABLE_ISSUES, null, selection, selArgs, null, null, null);
c.moveToFirst();
return c;
}
嗯,返回Cursor
是空的。为什么呢?
sqlite> select count (*) from issues where project_id = '1';
0
嗯,这就是原因。
我发现的唯一解决方案是:
public Cursor selectAllCursor(final long projectId) {
final String selection = projectId > 0 ? KEY_PROJECT + " = " + projectId : null;
final String[] selArgs = null;
final Cursor c = mDb.query(TABLE_ISSUES, null, selection, selArgs, null, null, null);
c.moveToFirst();
return c;
}
它有效,但我觉得这很难看
为什么选择参数不是Object
而不是String
的数组? Android框架将测试对象类型,如果它是一个整数(int
/ long
),它会告诉SQLite将其视为整数。
答案 0 :(得分:1)
参数对于避免字符串格式化问题(包括SQL注入攻击)非常有用。 对于其他类型,您没有这样的问题。
但这仍然意味着您必须使用完全不同的代码,具体取决于值的类型。 此外,如果您使用compileStatement,可以使用其他类型作为参数,但SQLiteStatement仅适用于单个值(1 x 1)结果集。
这只是简单的错误的API设计。
如果您将表格列声明为INTEGER
,则SQLite的type affinity rules会自动将该值转换回数字。
但是,这仅适用于Column = ?
等直接比较。
答案 1 :(得分:0)
你是对的,documentation非常明确,参数将始终绑定为字符串。不确定为什么(因为那是你的实际问题:-)),但无法找到解决方法。
selectionArgs您可以在选择中包含?,它将被selectionArgs中的值替换,以便它们出现在选择中。 这些值将绑定为字符串。
使用String.format做一个“更好”的方式来做你所拥有的东西? 例如
String selection = String.format("%s = %d", KEY_PROJECT, projectId )