Android栏'_id'不存在?


73

我在记事本示例中无法正常工作。这是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 实用程序并运行SQLite3。我检查了以下架构:

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创建表android_metadata(语言环境TEXT);创建表圈(_id整数主键自动递增,序列整数,半径实数,x实数,y实数);

我看不到我怎么想念'_id'。

我做错了什么?

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


1
您能否提供有关如何创建游标以及也许如何打开数据库的更多详细信息?
EboMike

3
您是否从选择的_ID列返回?检查您的光标创建。
Pentium10年

Answers:


153

我看到,CursorAdapter文档指出:

游标必须包含一个名为的列,_id否则此类将无法工作。

SimpleCursorAdapter是一个派生类,所以会出现这种情况适用。但是,该声明在技术上是错误的,并且在某种程度上误导了新手。游标的结果集必须包含_id,而不是游标本身。
我确信对于DBA来说这很清楚,因为这类速记文档对他们来说很清楚,但是对于那些新手来说,语句中的不完整会引起混淆。游标就像迭代器或指针,它们只包含一种用于遍历数据的机制,它们本身不包含任何列。

装载机文档包含在那里可以使可见的例子_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");
}

15
我建议将文档中的语句写为“游标的结果集必须包含一个名为“ _id”的列。否则将产生RuntimeException。这将减少混乱和纠正。
user405821

6
@ user405821-谢谢您-这个家伙并没有将您的答案标记为正确-但这是对Android的一部分的很好的补充,而该部分文献记录不多。+1
tpow 2010年

我在使用Google边栏评注的android文档中做了一个注释。边栏评注适用于这种情况,我希望更多的人将其与android文档一起使用。developer.android.com/reference/android/widget/...
奔^ h

噢,伙计,这是给您的惊人的Android SDK +文档!非常感谢您的回答。我花了一个多小时试图找出问题所在。
the_dark_destructor

谢谢!在我的情况下,错误是由于大写v / s小写的问题引起的。
Vish

107

这已经得到回答,我想在这里进行更全面的介绍。

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

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

如何覆盖getItemId并提供我自己的已定义ID?能解决问题吗?
fikr4n 2012年

@ max4ever具有最佳答案。这是解决此问题的完美解决方案。无需开始在数据库中创建不必要的_id列
Mike Baxter 2013年

+1,在查询中使用“ rowid _id”确实很有帮助。但是如果Android的默认数据库实现创建rowid密钥而其默认的游标适配器需要密钥,那么Android真是一团糟_id
Stan

也为我工作。这是使我免于将_id添加到数据库中的答案。
TryinHard

20

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列。添加,解决了我的问题。


这是所有解决方案都无法解决问题的时候。万事俱备。
tom_mai78101 2013年

6

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


这是一个容易犯的错误;官方文档说使用_ID。

0

如果您在sqlite上阅读文档,则创建任何类型为INTEGER PRIMARY KEY的列都会在内部对ROWID进行别名,因此不值得在每个SELECT中添加别名的麻烦,这与任何可能利用诸如定义表的列的枚举。

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

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


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.