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

Когда я запускаю свое приложение, я получаю исключение RuntimeException и следующие отпечатки в LogCat из моего оператора Log.e():

Сообщение LogCat:

java.lang.IllegalArgumentException: column '_id' не существует

Итак, вернемся к SQLite 3, чтобы узнать, что отличается от моей схемы:

sqlite > .schema CREATE TABLE android_metadata (locale TEXT); CREATE TABLE круги (_id целочисленный первичный ключ автоинкремент, последовательность целое число, радиус real, x real, y real);

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

Что я сделал неправильно?

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

Ответ 1

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

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

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

Документация загрузчиков содержит пример, где можно увидеть, что _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");
}

Ответ 2

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

SimpleCursorAdapter требует, чтобы набор результатов Cursor должен содержать столбец с именем точно "_id" . Не спешите изменять схему, если вы не указали столбец "_id" в своей таблице. SQLite автоматически добавляет скрытый столбец с именем "rowid" для каждой таблицы. Все, что вам нужно сделать, это просто выбрать rowid явно и псевдоним как "_id" Ex.

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

Ответ 3

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

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

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

Ответ 4

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

Ответ 5

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

Ответ 6

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

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

Ответ 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