Android - SQLiteStatement (множественная вставка) выполнить не удается с API уровня 14 - PullRequest
5 голосов
/ 26 февраля 2012

Я использую следующий код для эффективной вставки новых строк в БД:

@Override
public void insertImpacts(HolderExpense expense, int[] shares, int[] amounts, HolderUser[] users) {

    try {

        mDb.beginTransaction(); // the insertion of the impacts of one expense are considered to be ONE block

        String sql = "INSERT INTO "+DATABASE_TABLE_IMPACTS+" "+
        "("+IMPACT_USERROWID+", "+IMPACT_EXPENSEROWID+", "+IMPACT_TTROWID+", "+IMPACT_NUMBEROFPARTS+", "+IMPACT_FIXEDAMOUNT+") VALUES (?, ?, ?, ?, ?)";

        SQLiteStatement stmt = mDb.compileStatement(sql);

        stmt.bindLong(2, expense.rowId);
        stmt.bindLong(3, expense.tt.rowId);

        int i = 0;

        while (i < shares.length) {

            if (users[i] != null) {

                Log.v(TAG, "user " +i+": users[i].rowId:"+users[i].rowId+" expense.rowId:"+expense.rowId+" expense.tt.rowId:"+expense.tt.rowId+" shares[i]:"+shares[i]+" amounts[i]:"+amounts[i]+" ");

                stmt.bindLong(1, users[i].rowId);
                stmt.bindString(4, shares[i]+"");
                stmt.bindString(5, amounts[i]+"");

                stmt.execute();

            }
            i++;
        }

        stmt.close();

        mDb.setTransactionSuccessful();

    } 
    catch (Exception e) { e.printStackTrace(); throw new RuntimeException("insertImpacts() failed"); } 
    finally { mDb.endTransaction(); }

}

Это работает до Android 4.x, где я получаю эту ошибку:

02-26 14:27:46.179: W/System.err(937): android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed

02-26 14:27:46.179: W/System.err(937):  at android.database.sqlite.SQLiteStatement.native_execute(Native Method)

02-26 14:27:46.219: W/System.err(937):  at android.database.sqlite.SQLiteStatement.executeUpdateDelete(SQLiteStatement.java:92)

02-26 14:27:46.219: W/System.err(937):  at android.database.sqlite.SQLiteStatement.execute(SQLiteStatement.java:70)

Кажется, что происходит сбой в stmt.execute () при вставке второй строки в таблицу.

Любая подсказка?

- EDITION -

Схема таблицы следующая:

 private static final String DATABASE_CREATE_TABLE_IMPACTS =
        "create table " + DATABASE_TABLE_IMPACTS + " (" 
        + IMPACT_ROWID + " integer primary key autoincrement, "
        + IMPACT_USERROWID + " integer not null, "
        + IMPACT_EXPENSEROWID + " integer not null, "
        + IMPACT_TTROWID + " integer not null, "
        + IMPACT_NUMBEROFPARTS + " integer not null, "
        + IMPACT_FIXEDAMOUNT + " integer not null, "
        + "constraint i_cstr1 unique ("+IMPACT_USERROWID+", "+IMPACT_EXPENSEROWID+")); ";

Этот код работает как брелок на Android 2.2 (но не работает на Android 4.0).

Печать двух первых строк, которые я вставил (происходит сбой при попытке вставить вторую):

02-26 14:27:46.069: E/DatabaseAdapter.java(937): user 0: users[i].rowId:7 expense.rowId:2 expense.tt.rowId:2 shares[i]:1 amounts[i]:-1 
02-26 14:27:46.069: E/DatabaseAdapter.java(937): user 1: users[i].rowId:5 expense.rowId:2 expense.tt.rowId:2 shares[i]:1 amounts[i]:-1 

Ответы [ 2 ]

10 голосов
/ 26 февраля 2012

Found. Разные версии андроида не ведут себя одинаково. В Android 4.x все строки 'bindXXX' должны быть помещены в цикл while. Даже если это повторяется.

while (i < shares.length) {

    if (users[i] != null) {

        stmt.bindLong(1, users[i].rowId);
        stmt.bindLong(2, expense.rowId);
        stmt.bindLong(3, expense.tt.rowId);
        stmt.bindString(4, String.valueOf(shares[i]));
        stmt.bindString(5,  String.valueOf(amounts[i]));

        stmt.execute();
    }

    i++;

}
1 голос
/ 17 октября 2014

Это идеальный Гилбу!Я также сделал ваше решение для привязки данных для моей задачи: импорт файла CSV в базу данных SQLite.В CSV-файле было около 25 000 строк, и его импорт и вставка в SQLite заняли у меня около 5 секунд (прежде чем это заняло 5 минут без привязки данных !!)

Большое вам спасибо!

Я тоже поделюсь своим, может быть, это тоже кому-то поможет (Android 4.0):

public boolean updateFromCsv() {

    boolean ok = true;
    String line = "";
    BufferedReader br = null;

    try {
        FileInputStream fis = new FileInputStream(Environment
                .getExternalStorageDirectory().getAbsolutePath()
                + "/Servantes/Be/leltariv_export.csv");
        br = new BufferedReader(new InputStreamReader(fis));
    } catch (FileNotFoundException e) {
        ok = false;
        e.printStackTrace();
    }       
    try {

        database.beginTransaction(); 

        String sql = "INSERT INTO "+LeltarTable.TABLE_LELTAR_NEV+" "+
        "("+LeltarTable.COLUMN_ID+", "+LeltarTable.COLUMN_LSZ+", "+LeltarTable.COLUMN_MEGN+", "+LeltarTable.COLUMN_HELY+", "+LeltarTable.COLUMN_DARAB+") VALUES (?, ?, ?, ?, 0)";

        SQLiteStatement stmt = database.compileStatement(sql);

        while ((line = br.readLine()) != null) {
            String[] colums = line.split(";");
            stmt.bindAllArgsAsStrings(colums);
            stmt.execute();
}
        stmt.close();

        database.setTransactionSuccessful();

    }catch (Exception e) {
        e.printStackTrace();
        ok = false;
    }
    finally { 
        try {
            br.close();
        } catch (IOException e) {
            e.printStackTrace();
            ok = false;
        }
        database.endTransaction(); 
        }

    return ok;
}
...