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