2010-07-29 21 views
65

Tengo problemas con algo que funciona en el ejemplo del Bloc de notas. Aquí está el código de la NotepadCodeLab/Notepadv1Solution:La columna de Android '_id' no existe?

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

Este código parece funcionar bien. Pero para ser claros, me encontré con la ADB utilidad y corro SQLite 3. inspeccioné el esquema de la siguiente manera:

sqlite> .schema

CREATE TABLE android_metadata (locale TEXT); 
CREATE TABLE notes (_id integer primary key autoincrement, title text 
not null, body text not null); 

Todo parece bueno para mí.


Ahora a mi solicitud, la cual, por lo que yo puedo ver, es básicamente lo mismo con algunos cambios menores. Simplifiqué y simplifiqué mi código, pero el problema persiste.

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

Cuando ejecuto mi aplicación, me sale un RuntimeException y las siguientes impresiones en LogCat de mi declaración Log.e():

LogCat mensaje:

java.lang.IllegalArgumentException: la columna ' _id 'no existe

Así que, regrese a SQLite 3 para ver qué hay de diferente en mi sc hema:

sqlite> .schema CREAR TABLA android_metadata (locale TEXT); Círculos CREATE TABLE (_id autoincrement de clave primaria entera, secuencia entero, radio real, x real, y real);

No veo cómo me falta el '_id'.

¿Qué he hecho mal?

Una cosa que es diferente entre mi aplicación y el ejemplo del Bloc de notas es que comencé creando mi aplicación desde cero utilizando el asistente de Eclipse mientras la aplicación de muestra ya está ensamblada. ¿Es algún tipo de cambio ambiental que necesito hacer para una nueva aplicación para usar una base de datos SQLite?

+1

¿Puede proporcionar más detalles sobre cómo se creó el cursor, y tal vez la forma en que se abrió la base de datos? – EboMike

+3

¿Vuelve desde su selección la columna _ID? Verifica la creación de tu cursor. – Pentium10

Respuesta

145

veo, los estados documentation for CursorAdapter:

el cursor debe incluir una columna llamada o _id Esta clase no trabajo.

La SimpleCursorAdapter es una clase derivada, por lo que parece que esta afirmación es aplicable. Sin embargo, la declaración es técnicamente incorrecta y un tanto engañosa para un novato. El conjunto de resultados para el cursor debe contener _id, no el cursor en sí.
Estoy seguro de que esto es claro para un DBA porque ese tipo de documentación taquigráfica es clara para ellos, pero para los novatos, estar incompleto en la declaración causa confusión.Los cursores son como iteradores o punteros, no contienen nada más que un mecanismo para atravesar los datos, no contienen columnas.

El Loaders documentation contiene un ejemplo donde puede verse que la _id está incluido en la proyección parámetro .

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"); 
} 
+14

Recomiendo que la declaración en la documentación se escriba como "El conjunto de resultados del Cursor debe incluir una columna llamada exactamente" _id ". De lo contrario, se generará una RuntimeException". Esto sería menos confuso y correcto. – user405821

+6

@ user405821 - Gracias, hombre - este tipo no marcó tu respuesta como correcta - pero esta fue una excelente adición a una parte de Android que está mal documentada. +1 – tpow

+0

hice una nota sobre en los documentos de Android usando google sidewiki. sidewiki es perfecto para este tipo de cosas, y espero que más personas lo utilicen junto con la documentación de Android. http://developer.android.com/reference/android/widget/CursorAdapter.html –

101

Ésta ha sido answered y me gustaría para que sea más amplio aquí.

SimpleCursorAdapter requiere que el conjunto de resultados del Cursor debe incluir una columna llamada exactamente "_id". No se apresure a cambiar el esquema si no definió la columna "_id" en su tabla. SQLite agregó automáticamente una columna oculta llamada "rowid" para cada tabla. Todo lo que necesita hacer es seleccionar rowid explícitamente y alias como '_id' Ej.

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

o seleccione id como _id – max4ever

+2

mejor respuesta para resolver el problema. – Mihir

+0

¿Qué hay sobre la anulación de 'getItemId' y proporcionar mi propia identificación definida? ¿Puede resolver el problema? – BornToCode

5

Sí, también cambio la consulta SELECT de cadenas para solucionar este problema.

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

Esto probablemente ya no sea relevante, pero hoy me sale el mismo problema. Resulta que los nombres de las columnas son sensibles a mayúsculas y minúsculas. Tenía una columna _ID, pero Android espera una columna _id.

+0

Esto es un error fácil de hacer; la documentación oficial dice que use _ID. –

19

código de Tim Wu realmente funciona ...

Si está utilizando db.query, entonces sería así ...

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

¡Genial! Gracias una tonelada. Guardé que mi base de datos no se confundiera con _id. Guardado mi día – TryinHard

+0

@TryinHard: De nada :-) – Deepzz

7

Lo resolvió mi problema con este error era que yo no había incluido la columna _id en mi consulta DB. Agregar eso resolvió mi problema.

+0

Esto es cuando todas las soluciones no solucionan el problema. El último recurso para todo. –

0

Si lee los documentos en sqlite, al crear cualquier columna de tipo INTEGER PRIMARY KEY se creará un alias interno de ROWID, por lo que no vale la pena agregar un alias en cada SELECT, desviándose de las utilidades comunes que podrían tomarse ventaja de algo así como una enumeración de columnas que definen la tabla.

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

También es más fácil de usar esto como el ROWID en lugar de la opción AutoIncrement que puede causar _ID puede desviarse de la ROWID. Al vincular _ID a ROWID, significa que la clave primaria se devuelve desde insert/insertOrThrow; si escribe un ContentProvider, puede usar esta clave en el Uri devuelto.

0

Otra forma de lidiar con la falta de una columna _id en la tabla es escribir una subclase de CursorWrapper que añada una columna _id si es necesario.

Esto tiene la ventaja de que no requiere ningún cambio en las tablas o consultas.

He escrito una clase tal, y si es de cualquier interés que se puede encontrar en https://github.com/cmgharris/WithIdCursorWrapper

Cuestiones relacionadas