2012-02-26 27 views
5

मैं निम्नलिखित कोड का उपयोग एक DB में कुशलता से नई लाइनें डालने के लिए के साथ विफल:एंड्रॉयड SQLiteStatement (एकाधिक डालने) पर अमल एपीआई स्तर 14

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

} 

यह एंड्रॉयड 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() पर क्रैश होता है।

कोई सुराग?

- संस्करण -

तालिका के स्कीमा है निम्नलिखित:

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

इस कोड को एंड्रॉयड 2.2 पर एक आकर्षण की तरह काम करता है (लेकिन एंड्रॉयड 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

ठीक है, लगता है कि आप एक बाधा का उल्लंघन कर रहे हैं। आपकी टेबल स्कीमा क्या है? – Mat

+0

मैं @Mat से सहमत हूं, आपको अपना निर्माण तालिका विवरण पोस्ट करना चाहिए। – dmon

+0

हाय मैट। मैंने टेबल के स्कीमा के साथ अपना प्रश्न संपादित किया। – Gilbou

उत्तर

10

मिले। एंड्रॉइड का अलग संस्करण वही व्यवहार नहीं करता है। एंड्रॉइड 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++; 

} 
+0

उत्कृष्ट - इसके लिए धन्यवाद। मैंने 4.x –

+1

के तहत ** सभी ** पैरामीटर को पुनर्निर्मित करने के बारे में कभी सोचा नहीं होगा। 'बूलियन' मानों को कैसे बाध्य करें। –

+0

@ प्रैटिक: सुनिश्चित नहीं है कि आपको अभी तक आपका जवाब मिल गया है लेकिन SQLite में बुलियन प्रकार नहीं है। आपको अन्य प्रकारों में से एक का उपयोग करने की आवश्यकता है। मैं एक पूर्णांक 0/1 का उपयोग करता हूं और इनपुट/आउटपुट पर कनवर्ट करता हूं। –

1

यह सही Gilbou है! मैंने अपने कार्य के लिए अपना डेटा बाइंडिंग समाधान भी बनाया: सीएसवी फ़ाइल SQLite डेटाबेस में आयात कर रही है। सीएसवी फ़ाइल में लगभग 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; 
}