java.lang.Исключение IllegalArgumentException: столбец ‘_id’ не существует

#android #android-sqlite

#Android #android-sqlite

Вопрос:

Я пытаюсь отладить свое приложение на реальном устройстве, но я получаю эту ошибку:

ОШИБКА / AndroidRuntime(981): вызвано: java.lang.Исключение IllegalArgumentException: столбец ‘_id’ не существует

Когда я тестирую на эмуляторе, ошибка не появляется. Ошибка указана в последней строке следующего кода:

 adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {   
            DataHandlerDB.CONTACT_NAME_COL,
            DataHandlerDB.CONTACT_NUMBER_COL,
            DataHandlerDB.CONTACT_DURATION_COL,
            DataHandlerDB.CONTACT_DATE_COL }, new int[] {
            R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });
  

Вот моя активность:

 public class MyActivity extends Activity {

    private static final String LOG_TAG = "MyActivity";
    private ListView listview;
    private SimpleCursorAdapter adapter;        
    private DataHandlerDB handler;
    private SQLiteDatabase db;
    private OpenHelper helper;
    private Cursor c;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);     
        setContentView(R.layout.main);

        helper = new OpenHelper(this);
        db = helper.getWritableDatabase();
        helper.onCreate(db);
        setBasicContent();
        c.close();
    }   


    @Override
    public void onDestroy(){

        super.onDestroy();
        DataHandlerDB.makeTheSelection(this).close();
        db.close();
        helper.close();

    }

    @Override
    public void onPause(){

        super.onPause();
        DataHandlerDB.makeTheSelection(this).close();
        db.close();
        helper.close();

    }

    @Override
    public void onStop(){

        super.onStop();
        DataHandlerDB.makeTheSelection(this).close();
        db.close();
        helper.close();

    }


    @Override
    protected void onResume(){

        super.onResume();
        setBasicContent();

    }   

    public void setBasicContent() {

        listview = (ListView) findViewById(R.id.list_view); 

        Log.i(LOG_TAG, "listview "   listview);

        c = DataHandlerDB.makeTheSelection(this);

        c.moveToFirst();

        if(db.isOpen())
            Log.i(LOG_TAG, "db is opened");

        Log.i(LOG_TAG, "cursor: "   c.getCount());

        startManagingCursor(c);

        adapter = new SimpleCursorAdapter(this, R.layout.list_item, c, new String[] {   
                DataHandlerDB.CONTACT_NAME_COL,
                DataHandlerDB.CONTACT_NUMBER_COL,
                DataHandlerDB.CONTACT_DURATION_COL,
                DataHandlerDB.CONTACT_DATE_COL }, new int[] {
                R.id.contact_name, R.id.phone_number, R.id.duration, R.id.date });

        Log.i(LOG_TAG, "before setAdapter");
        Toast.makeText(this, "Before setAdapter", Toast.LENGTH_SHORT).show();

        listview.setAdapter(adapter);

        db.close();

        if(db.isOpen()){

            Log.i(LOG_TAG, "db is opened.");

        }

        if(!c.isClosed()){

            Log.i(LOG_TAG, "cursor is opened");

        }           
    }       
}
  

Функция, которая запрашивает и возвращает Cursor , находится в классе DataHandlerDB :

 public class DataHandlerDB {

private static final String DATABASE_NAME = "calls.db";
private static final int DATABASE_VERSION = 1;

protected static String CONTACT_NAME_COL = "contact_name";
protected static String CONTACT_NUMBER_COL = "contact_number";
protected static String CONTACT_DURATION_COL = "duration";
protected static String CONTACT_DATE_COL = "date";
protected static String CONTACT_MONTH_COL = "month";

// create the DB
public static SQLiteDatabase createDB(Context ctx) {
    OpenHelper helper = new OpenHelper(ctx);
    SQLiteDatabase db = helper.getWritableDatabase();
    helper.onCreate(db);
    helper.onOpen(db);
    db.close();
    return db;
}

public static Cursor makeTheSelection(Context ctx) {

    OpenHelper helper = new OpenHelper(ctx);
    SQLiteDatabase db = helper.getWritableDatabase();

    Cursor cursor = db.query(TABLE_NAME_2, null, null, null, null, null,
            "duration desc");

    cursor.moveToFirst();
    db.close();

    return cursor;
}
    // class OpenHelper
public static class OpenHelper extends SQLiteOpenHelper {

    private final Context mContext;

    OpenHelper(Context context) {

        super(context, DATABASE_NAME, null, DATABASE_VERSION);
        this.mContext = context;

    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        Log.i(LOG_TAG, "entrou no onCreate");
        String[] sql = mContext.getString(
                R.string.MyAppDatabase_OnCreate).split("n");

        db.beginTransaction();

        try {
            execMultipleSQL(db, sql);
            db.setTransactionSuccessful();
        } catch (SQLException e) {

            Log.e("Error creating tables and debug data", e.toString());
            throw e;

        } finally {
            db.endTransaction();

        }
    }

    private void execMultipleSQL(SQLiteDatabase db, String[] sql) {

        for (String s : sql) {

            if (s.trim().length() > 0) {

                db.execSQL(s);
            }
        }

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

         Log.w("MyDB Database",
         "Upgrading database, this will drop tables and recreate.");
         db.execSQL("DROP TABLE IF EXISTS "   TABLE_NAME); onCreate(db);

    }

    @Override
    public void onOpen(SQLiteDatabase db) {

        super.onOpen(db);
    }
}
}
  

Вот XML-файл с командой SQL:

 <string name="MyAppDatabase_OnCreate">
    "CREATE TABLE IF NOT EXISTS contact_data(_id INTEGER PRIMARY KEY AUTOINCREMENT, contact_id INTEGER, contact_name VARCHAR(50), number_type VARCHAR(50), contact_number VARCHAR(50), duration TIME, duration_sum TIME, date DATE, current_time TIME, cont INTEGER, type VARCHAR, month VARCHAR(50), day VARCHAR(50), year VARCHAR(50));"
</string>
  

Я думаю, что приложение не создает базу данных при первом запуске. Я так думаю, потому что он может найти столбец _id , но в XML-коде явно написано создать его с помощью _id столбца. Я также думаю, что, поскольку я явно написал столбцы в SELECT методе, включая _id . Я сделал это следующим образом:

 Cursor cursor = db.query(TABLE_NAME_2, 
                new String[]{
                "_id", 
                "contact_id", 
                "contact_name", 
                "number_type", 
                "contact_number", 
                "duration", 
                "duration_sum", 
                "date", 
                "current_time", 
                "cont", "type", 
                "month", 
                "day", 
                "year"}, null, null, null, null,
                "duration desc");
  

В этом случае ошибка, которую я получаю, почти такая же:

Вызвано: android.database.sqlite.Исключение SQLiteException: нет такого столбца: _id: , при компиляции: ВЫБЕРИТЕ _id, contact_id, contact_name, number_type, contact_number, duration, duration_sum, date, current_time, продолжение, тип, месяц, день, год ИЗ contact_data УПОРЯДОЧИТЬ ПО длительности desc

Я зарегистрировал первый столбец базы данных следующим образом:

 Log.i(LOG_TAG, "Cursor(0)"   cursor.getColumnName(0));
  

Он напечатан id , не _id . Как вы можете видеть, в инструкции _id написано. Есть предложения о том, как решить эту проблему?

Комментарии:

1. Полностью удалите приложение с устройства (например, Настройки> Приложения> Управление приложениями) и повторите попытку. Я подозреваю, что ваша база данных уже существовала без _id столбца.

2. Я сделал, как вы сказали, но ошибка сохраняется. = (

3. @CommonsWare благодарю бога за этот ответ… Я думал, что это проблема с кодированием, но это был такой тривиальный случай!

Ответ №1:

Вы пытаетесь использовать курсор, для которого ТРЕБУЕТСЯ столбец с именем _id . Это так же просто, как отредактировать инструкцию создания таблицы и добавить столбец с именем _id.

Его объявление выглядит примерно так:

 _id INTEGER PRIMARY KEY AUTOINCREMENT
  

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

Обновить

 "CREATE TABLE IF NOT EXISTS contact_data( _id INTEGER PRIMARY KEY AUTOINCREMENT, contact_id INTEGER, contact_name VARCHAR(50), number_type VARCHAR(50), contact_number VARCHAR(50), duration TIME, duration_sum TIME, date DATE, current_time TIME, cont INTEGER, type VARCHAR, month VARCHAR(50), day VARCHAR(50), year VARCHAR(50));"
  

Решение: добавьте пробел между левой круглой скобкой ‘(‘ и _id

Комментарии:

1. CursorAdapter требуется, чтобы столбец вызывался _id всегда.

2. Вы можете использовать псевдоним вместо его создания! Если у вас уже есть столбец _id, но у него другое имя, просто измените имя вашего первичного ключа, используя AS в вашем sql-запросе: { ВЫБЕРИТЕ myprimarykey КАК _id, имя Из таблицы, ГДЕ имя ПОХОЖЕ НА ‘%queryfilter%’; }

3. Основываясь на точке зрения @jcasadellaoller: db.query("tableName", new String[]{"current_id _id", ... Это означает, что вы можете использовать существующую таблицу, но запрос будет использовать псевдоним вашего «current_id» в качестве требуемого столбца «_id», так что это будет так, как если бы этот столбец существовал

Ответ №2:

У меня была похожая проблема, потому что я не добавлял столбец _id к аргументу projection, поэтому добавление _id к аргументу projections запроса было решением. (прокомментировано @nobugs)


Пример:

  String[] projections = {"_id", "name", "age"};

 Cursor cursor = db.query(domainClass.getSimpleName(), projections, 
     null, null, null, null, null);
  

Комментарии:

1. Это было решением для меня. Глупый я. Спасибо.

Ответ №3:

Прежде всего удалите приложение, а затем выполните следующие действия:

  1. Очистите проект
  2. перестроить проект
  3. отладьте приложение (Shift F9)

Ответ №4:

CursorAdapter всегда требует наличия _id столбца. Итак, в список проекций, используемых для создания курсора, вам нужно добавить _id столбец.

Ответ №5:

Я сделал это и решил свою проблему.

Перед

SELECT id

После

SELECT id as _id