Столбец Android '_id' не существует? - PullRequest
70 голосов
/ 29 июля 2010

У меня проблемы с чем-то, что работает в примере с Блокнотом.Вот код из 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 CREATE TABLE android_metadata (локаль TEXT);Круги CREATE TABLE (автоинкремент первичного ключа целого числа _id, целое число последовательности, вещественное число радиуса, действительное число x, действительное число y);

Я не вижу, как мне не хватает _id.

Что я сделал не так?

Одна вещь, которая отличается от моего приложения и примера Блокнота, состоит в том, что я начал с создания своего приложения с нуля с помощью мастера Eclipse, в то время как пример приложения уже собран.Есть ли какие-то изменения в окружающей среде, которые мне нужно сделать, чтобы новое приложение использовало базу данных SQLite?

Ответы [ 8 ]

149 голосов
/ 29 июля 2010

Я вижу, документация для CursorAdapter гласит:

Курсор должен включать столбец с именем _id, иначе этот класс не будет работа.

SimpleCursorAdapter является производным классом, поэтому, похоже, это утверждение применимо. Тем не менее, это заявление технически неправильно и несколько вводит в заблуждение новичка. набор результатов для курсора должен содержать _id, а не сам курсор.
Я уверен, что это понятно для администратора баз данных, потому что такая краткая документация им понятна, но для этих новичков, неполное в заявлении вызывает путаницу. Курсоры похожи на итераторы или указатели, они не содержат ничего, кроме механизма перемещения данных, сами по себе не содержат столбцов.

Документация 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");
}
103 голосов
/ 21 сентября 2011

Это было ответ , и я хотел бы сделать его более полным здесь.

SimpleCursorAdapter требует, чтобы результирующий набор Курсора включал столбец с именем «_id». Не спешите менять схему, если вы не определили столбец «_id» в своей таблице. SQLite автоматически добавляет скрытый столбец с именем «rowid» для каждой таблицы. Все, что вам нужно сделать, это просто явно указать rowid и присвоить ему псевдоним '_id'.

SQLiteDatabase db = mHelper.getReadableDatabase();      
Cursor cur =  db.rawQuery( "select rowid _id,* from your_table", null);
20 голосов
/ 29 сентября 2012

Код Тима Ву действительно работает ...

Если вы используете db.query, то это было бы так ...

db.query(TABLE_USER, new String[] { 
                "rowid _id",
                FIELD_USERNAME,
                }, 
                FIELD_USERNAME + "=" + name, 
                null, 
                null, 
                null, 
                null);
7 голосов
/ 04 июня 2013

Что решило мою проблему с этой ошибкой, так это то, что я не включил столбец _id в запрос к БД.Добавление, которое решило мою проблему.

7 голосов
/ 22 сентября 2011

Да, я также изменяю запрос строки SELECT, чтобы исправить эту проблему.

String query = "SELECT t.*,t.id as _id FROM table t "; 
6 голосов
/ 17 ноября 2011

Возможно, это больше не актуально, но сегодня я столкнулся с той же проблемой.Оказывается, имена столбцов чувствительны к регистру.У меня был столбец _ID, но Android ожидает столбец _id.

0 голосов
/ 30 июня 2014

Другой способ справиться с отсутствием столбца _id в таблице - написать подкласс CursorWrapper, который добавляет столбец _id при необходимости.

Преимущество в том, что не требуется никаких изменений в таблицах или запросах.

Я написал такой класс, и, если он представляет какой-либо интерес, его можно найти по адресу https://github.com/cmgharris/WithIdCursorWrapper

0 голосов
/ 13 сентября 2013

Если вы читаете документацию по sqlite, создание любого столбца типа INTEGER PRIMARY KEY внутренне создаст псевдоним ROWID, поэтому не стоит добавлять псевдоним в каждый SELECT, отклоняясь от любых распространенных утилит, которые могут использовать что-то вроде перечисления столбцов, определяющих таблицу.

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

Также более просто использовать это в качестве ROWID вместо опции AUTOINCREMENT, которая может привести к отклонению _ID от ROWID. Привязав _ID к ROWID, это означает, что первичный ключ возвращается из insert / insertOrThrow; если вы пишете ContentProvider, вы можете использовать этот ключ в возвращенном Uri.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...