【问题标题】:Android column '_id' does not exist?Android列'_id'不存在?
【发布时间】:2011-03-22 12:36:59
【问题描述】:

我在使用记事本示例时遇到了问题。 这是来自 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 和以下打印 在我的 Log.e() 声明中的 LogCat 中:

LogCat 消息:

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

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

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

我看不出我是怎么错过“_id”的。

我做错了什么?

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

【问题讨论】:

  • 您能否提供更多有关您如何创建游标以及您如何打开数据库的详细信息?
  • 您是否从选择_ID 列返回?检查您的光标创建。

标签: android listview sqlite


【解决方案1】:

我明白了,documentation for CursorAdapter 声明:

游标必须包含名为_id 的列,否则此类将不会 工作。

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

Loaders documentation 包含一个示例,可以看出 _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");
}

【讨论】:

  • 我建议将文档中的语句写成“游标的结果集必须包含一个名为“_id”的列。否则将产生 RuntimeException。”这样会更容易混淆和正确。
  • @user405821 - 谢谢伙计 - 这个人没有将你的答案标记为正确 - 但这是对 Android 部分文档的极好补充。 +1
  • 我使用 google sidewiki 在 android 文档中做了一个注释。 sidewiki 非常适合这类事情,我希望更多的人将它与 android 文档结合使用。 developer.android.com/reference/android/widget/…
  • 天哪,这是为您准备的令人惊叹的 Android SDK + 文档!非常感谢您的回答。我花了一个多小时试图找出问题所在。
  • 谢谢!在我的情况下,错误是由于大写与小写的问题。
【解决方案2】:

这是answered,我想在这里更全面。

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

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

【讨论】:

  • 如何覆盖getItemId 并提供我自己定义的ID?能解决问题吗?
  • @max4ever 有最好的答案。它是这个问题的完美解决方案。无需开始在数据库中创建不必要的 _id 列
  • +1,在查询中使用“rowid _id”确实很有帮助。但是,如果它的默认 DB 实现创建 rowid 键,而它的默认光标适配器需要 _id,那么 Android 会是多么混乱?!
  • 也为我工作。这是使我免于将 _id 添加到数据库中的答案。
【解决方案3】:

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

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

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

【讨论】:

    【解决方案4】:

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

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

    【讨论】:

      【解决方案5】:

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

      【讨论】:

      • 这是所有解决方案都无法解决问题的时候。万事俱备的最后手段。
      【解决方案6】:

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

      【讨论】:

      • 这是一个容易犯的错误;官方文档说使用_ID。
      【解决方案7】:

      如果您阅读 sqlite 上的文档,创建任何 INTEGER PRIMARY KEY 类型的列都会在内部为 ROWID 设置别名,因此不值得在每个 SELECT 中添加别名的麻烦,偏离任何可能利用的常用实用程序类似于定义表的列的枚举。

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

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

      【讨论】:

        【解决方案8】:

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

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

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

        【讨论】:

          猜你喜欢
          • 2011-08-15
          • 2016-06-30
          • 1970-01-01
          • 2011-03-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多