Android列'_id'不存在?

我在记事本示例中遇到了一些麻烦。 以下是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); } 

当我运行我的应用程序时,从Log.e()语句中得到一个RuntimeException,并在LogCat中显示以下内容:

LogCat消息:

java.lang.IllegalArgumentException:列'_id'不存在

所以,回到SQLite 3来看看我的模式有什么不同:

sqlite> .schema CREATE TABLE android_metadata(locale TEXT); CREATE TABLE circles(_id integer primary key autoincrement,sequence integer,radius real,x real,y real);

我不明白我是如何错过'_id'的。

我做错了什么?

我的应用程序和记事本之间的一个不同之处在于,我开始使用Eclipse向导从头创build应用程序,而示例应用程序已经放在一起。 是否需要为使用SQLite数据库的新应用程序进行某种环境更改?

我看到, CursorAdapter的文档指出:

游标必须包含一个名为_id的列,否则这个类将不起作用。

SimpleCursorAdapter是一个派生类,所以看起来这个陈述适用。 然而,这个声明在技术上是错误的,并且对新手有些误导。 游标的结果集必须包含_id ,而不是游标本身。
我相信这对于DBA来说是清楚的,因为这种简明的文档对他们来说是清楚的,但是对于那些新手而言,陈述中的不完整会导致混淆。 游标就像迭代器或指针,它们不包含任何东西,只是一个横切数据的机制,它们本身不包含任何列。

Loaders文档包含一个示例,可以看到投影参数中包含_id

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

这已经得到了答复 ,我想在这里更全面。

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

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

Tim Wu的代码真的有效

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

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

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

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

是的,我也改变了SELECTstring查询来解决这个问题。

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

如果你阅读sqlite的文档,创build任何types的INTEGER PRIMARY KEY列将内部别名ROWID,所以这是不值得在每个SELECT中添加一个别名的麻烦,偏离任何可能利用类似的东西定义表的列的枚举。

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

将ROWIDreplace为AUTOINCREMENT选项可能会导致_ID可能偏离ROWID,这也更为直接。 通过将_ID绑定到ROWID,这意味着主键从insert / insertOrThrow返回; 如果您正在编写ContentProvider,则可以在返回的Uri中使用此密钥。

处理表中缺less_id列的另一种方法是编写CursorWrapper的子类,如果需要,它将添加_id列。

这具有不需要对表或查询进行任何更改的优点。

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