首页 文章

Android专栏'_id'不存在?

提问于
浏览
68

我在Notepad示例中遇到了一些问题 . 这是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 CREATE TABLE android_metadata(locale TEXT); CREATE TABLE圆圈(_id整数主键自动增量,序列整数,半径实数,x实数,y实数);

我不知道我是如何错过'_id'的 .

我做错了什么?

我的应用程序和Notepad示例之间的一个不同之处在于,我首先使用Eclipse向导从头创建应用程序,同时示例应用程序已经放在一起 . 我需要为新应用程序使用SQLite数据库进行某种环境变更吗?

8 回答

  • 102

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

    如果您正在使用db.query,那么它就像这样......

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

    如果您阅读sqlite上的文档,创建INTEGER PRIMARY KEY类型的任何列将在内部为ROWID设置别名,因此在每个SELECT中添加别名都是不值得的,这与可能利用类似的东西的任何常用实用程序不同定义表的列的枚举 .

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

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

  • 20

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

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

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

  • 7

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

  • 7

    我明白了,documentation for CursorAdapter说:

    Cursor必须包含名为_id的列,否则此类将不起作用 .

    SimpleCursorAdapter 是派生类,因此该语句似乎适用 . 然而,该声明在技术上是错误的,并且对新手有些误导 . 游标的 result set 必须包含 _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");
    }
    
  • 0

    是的,我还更改SELECT字符串查询以解决此问题 .

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

    这已经answered,我想在这里更全面 .

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

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

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

相关问题