Android 列“_id”不存在?

问题描述 投票:0回答:9

我在使用记事本示例中遇到问题。 这是来自 NotepadCodeLab/Notepadv1Solution 的代码:

String[] from = new String[] { NotesDbAdapter.KEY_TITLE };
int[] to = new int[] { R.id.text1 };

SimpleCursorAdapter notes = new SimpleCursorAdapter(this,
R.layout.notes_row, c, from, to);

这段代码似乎运行良好。 但为了清楚起见,我运行了 ADB 实用程序并运行 SQLite 3。我检查了架构,如下所示:

sqlite> .schema

CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE notes (_id integer primary key autoincrement, title text
not null, body text not null);

我觉得一切都很好。


现在开始我的应用程序,据我所知,它与 一些小的变化。 我已经简化了我的代码,但是 问题仍然存在。

String[] from = new String[] { "x" };
int[] to = new int[] { R.id.x };

SimpleCursorAdapter adapter = null;
try
{
    adapter = new SimpleCursorAdapter(this, R.layout.circle_row, cursor, from, to);
}
catch (RuntimeException e)
{
    Log.e("Circle", e.toString(), e);
}

当我运行我的应用程序时,我收到 RuntimeException 和以下打印内容 在 LogCat 中,来自我的

Log.e()
声明:

LogCat消息:

java.lang.IllegalArgumentException:列“_id”不存在

那么,回到 SQLite 3 看看我的架构有什么不同:

sqlite> .schema 创建表 android_metadata (语言环境文本); CREATE TABLE Circles(_id整型主键自增,序列 整数,半径实数,x 实数,y 实数);

我不明白我怎么会缺少“_id”。

我做错了什么?

我的应用程序和记事本示例之间的一个不同之处是 我首先使用以下命令从头开始创建我的应用程序 示例应用程序附带的 Eclipse 向导已经放在一起了。 是 我需要为新应用程序进行某种环境改变 使用 SQLite 数据库?

android listview sqlite
9个回答
155
投票

我明白了,CursorAdapter的文档指出:

光标必须包含名为

_id
的列,否则此类将不会 工作。

SimpleCursorAdapter
是派生类,因此看来此声明适用。然而,这种说法在技术上是错误的,并且对新手有些误导。 光标的 结果集 必须包含
_id
,而不是光标本身。
我确信 DBA 对此很清楚,因为这种速记文档对他们来说很清楚,但对于那些新手来说,声明中的不完整会导致混乱。 游标就像迭代器或指针,它们只包含一种遍历数据的机制,它们本身不包含列。

Loaders 文档包含一个示例,可以看出

_id
包含在 projection 参数中。

static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
    Contacts._ID,
    Contacts.DISPLAY_NAME,
    Contacts.CONTACT_STATUS,
    Contacts.CONTACT_PRESENCE,
    Contacts.PHOTO_ID,
    Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
    // ...
    return new CursorLoader(getActivity(), baseUri,
            CONTACTS_SUMMARY_PROJECTION, select, null,
            Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}

108
投票

这已经被回答了,我想在这里使它更全面。

SimpleCursorAdapter 要求 Cursor 的结果集必须包含名为“_id”的列。 如果您没有在表中定义“_id”列,请不要急于更改架构。 SQLite 自动为每个表添加一个名为“rowid”的隐藏列。 您需要做的就是显式选择 rowid 并将其别名为“_id”Ex。

SQLiteDatabase db = mHelper.getReadableDatabase();      
Cursor cur =  db.rawQuery( "select rowid _id,* from your_table", null);

21
投票

Tim Wu 的代码确实有效...

如果你使用db.query,那么它会是这样的......

db.query(TABLE_USER, new String[] { 
                "rowid _id",
                FIELD_USERNAME,
                }, 
                FIELD_USERNAME + "=" + name, 
                null, 
                null, 
                null, 
                null);

8
投票

是的,我还更改了 SELECT 字符串查询来解决这个问题。

String query = "SELECT t.*,t.id as _id FROM table t "; 

7
投票

解决此错误的问题是我没有在数据库查询中包含 _id 列。添加这解决了我的问题。


6
投票

这可能不再相关,但我今天遇到了同样的问题。结果列名区分大小写。我有一个 _ID 列,但 Android 需要一个 _id 列。


0
投票

如果您阅读 sqlite 上的文档,创建任何 INTEGER PRIMARY KEY 类型的列都会在内部为 ROWID 起别名,因此不值得在每个 SELECT 中添加别名,这偏离了可能利用某些功能的任何常见实用程序就像定义表的列的枚举一样。

http://www.sqlite.org/autoinc.html

使用它作为 ROWID 而不是 AUTOINCRMENT 选项也更直接,因为 AUTOINCRMENT 选项可能会导致 _ID 偏离 ROWID。通过将 _ID 与 ROWID 绑定,意味着主键是从 insert/insertOrThrow 返回的;如果您正在编写 ContentProvider,则可以在返回的 Uri 中使用此键。


0
投票

处理表中缺少 _id 列的另一种方法是编写 CursorWrapper 的子类,必要时添加 _id 列。

这样做的优点是不需要对表或查询进行任何更改。

我写了这样一个类,如果有兴趣可以在 https://github.com/cmgharris/WithIdCursorWrapper

找到它

0
投票

在我的例子中,数据库已经创建,没有 _id。所以我从设备资源管理器中删除了sqlite db文件,并将columnID更改为_id,然后它开始工作。

希望它能帮助别人! ;)

© www.soinside.com 2019 - 2024. All rights reserved.