【问题标题】:SQLite error inserting constraint field - why?SQLite 插入约束字段时出错 - 为什么?
【发布时间】:2020-04-09 14:31:52
【问题描述】:

我是 android 编程和使用 SQLite 的新手。我正在尝试插入一个名为“menu”的数据库,该数据库有一个名为“items”的表。该表的属性是“名称”和“价格”,它们分别是文本和实数。 (我想为所有代码道歉,但我认为这些代码会有用)。我的“MySQLiteHelper”类这样创建表:

package com.example.sqlite;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;

public class MySQLiteHelper extends SQLiteOpenHelper {

    //Creating the items table
    public  static final String TABLE_ITEMS = "items";
    public  static final String ITEMS_COLUMN_NAME = "name";
    public  static final String ITEMS_PRICE = "price";



    private static final String DATABASE_NAME  = "menu";
    private static final int DATABASE_VERSION  = 1;

    // create table comments(
    //   _id integer primary key autoincrement,
    //   comment text not null );
    private static final String TABLE_CREATE_ITEMS = "create table "
            + TABLE_ITEMS + "( " + ITEMS_COLUMN_NAME + " text primary key, "
            + ITEMS_PRICE + " real not null );";

    public MySQLiteHelper( Context context ) {
        super( context, DATABASE_NAME, null, DATABASE_VERSION );
    }

    @Override
    public void onCreate( SQLiteDatabase database ) {
        //Create the items table
        database.execSQL( TABLE_CREATE_ITEMS );
        //Create the combos table
        //database.execSQL(TABLE_CREATE_COMBO);
    }

    @Override
    public void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ) {
        Log.w( MySQLiteHelper.class.getName( ), "Upgrading database from version "
                + oldVersion + " to " + newVersion + ", which will destroy all old data" );
        db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_ITEMS );
        //db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_COMBO );
        onCreate( db );
    }
}

我可以确认数据库“菜单”是在 data/data/package/databases 文件夹中创建的。虽然我无法使用 adb shell 连接到 SQLite,所以我无法确认表模式。单击插入按钮后,我的 datasource.createComment(String, Float) 被调用:

public void onClick (View v) {
    @SuppressWarnings("unchecked")
    //Load up the current values in the adapter into this adapter object
            ArrayAdapter<Comment> adapter = (ArrayAdapter<Comment>)getListAdapter();
    //Set comment to null
    Comment comment = null;
    //Check to see which button was pressed
    switch (v.getId()) {
        case R.id.insert:
            String[] option = new String[] {"One", "Two", "Three"};
            int index = new Random().nextInt(3);
            //When inserting comment you just have to pass value
            comment = datasource.createComment("TEST", (float) 12.30);
            adapter.add(comment); //Adding to listview
            break;
        case R.id.delete:
            if(getListAdapter().getCount() > 0) {
                comment = (Comment)getListAdapter().getItem(0);
                adapter.remove(comment);//removing from listview
                datasource.deleteComment(comment); //delete from db.
            }
            break;
    }
    //Updating the adapter
    adapter.notifyDataSetChanged();
}

通过一些调试(打印语句),我可以确认 database.insert 返回 -1。插入不成功。在我的 Logcat 中打印出以下错误

12-16 23:42:30.002 11063-11063/com.example.sqlite E/SQLiteDatabase: Error inserting price=12.3 name=TEST
    android.database.sqlite.SQLiteConstraintException: error code 19: constraint failed
        at android.database.sqlite.SQLiteStatement.native_executeInsert(Native Method)
        at android.database.sqlite.SQLiteStatement.executeInsert(SQLiteStatement.java:113)
        at android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1718)
        at android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1591)
        at com.example.sqlite.CommentsDataSource.createComment(CommentsDataSource.java:47)
        at com.example.sqlite.InsertItems.onClick(InsertItems.java:50)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at android.view.View$1.onClick(View.java:3039)
        at android.view.View.performClick(View.java:3511)
        at android.view.View$PerformClick.run(View.java:14105)
        at android.os.Handler.handleCallback(Handler.java:605)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:137)
        at android.app.ActivityThread.main(ActivityThread.java:4424)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:511)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
        at dalvik.system.NativeStart.main(Native Method)

我的“CommentsDataSource”的代码如下。请忽略 createComment() 之后的方法。我正在一次编辑我的教授代码一种方法。

public class CommentsDataSource {

    // Database fields
    //Used toe xecute commands on db.
    private SQLiteDatabase database;
    //Opening up the mysqlhelper which is in charge of opening up connection and maintaining
    private MySQLiteHelper dbHelper;
    //Holds all the values from the database
    private String[] allColumnsItems = { MySQLiteHelper.ITEMS_COLUMN_NAME,
            MySQLiteHelper.ITEMS_PRICE };

    //Creating the default constructor
    public CommentsDataSource(Context context) {
        //Give context to the class that manages the connection
        dbHelper = new MySQLiteHelper(context);
    }

    //Opening up the connction to the db
    public void open() throws SQLException {
        //Open the db for reading and writing
        database = dbHelper.getWritableDatabase(); //getWritableDatabase is what opens the connection
    }

    //Closing the database
    public void close() throws SQLException {
        dbHelper.close();
    }

    //Creating and commiting comment
    public Comment createComment(String comment, float price) {
        //Insert into comments values('')
        ContentValues values = new ContentValues();
        //Load the column id and value into ContentValues
        values.put(MySQLiteHelper.ITEMS_COLUMN_NAME, comment);
        values.put("price", price);
        //Now insert into table
        long insertID = database.insert(MySQLiteHelper.TABLE_ITEMS, null, values);
        if(insertID == -1) {
            System.out.println("JSDLFJLSJDFL");
        }
        //Create a cursor to keep track of results. When creating cursors they equal database.query
        Cursor cursor =  database.query(MySQLiteHelper.TABLE_ITEMS, allColumnsItems, null, null, null, null, null);
        //Move cursor tot he front
        cursor.moveToFirst();
        //Return the comment which is added to listview
        return cursorToComment(cursor);
    }

    public void deleteComment(Comment comment) {
        // select id, comment from comments;
        long id = comment.getId();
        //Debug purposes
        System.out.println("Comment to be deleted: " + id);
        //Deleting from db
        database.delete(MySQLiteHelper.TABLE_ITEMS, MySQLiteHelper.ITEMS_COLUMN_NAME + "=" + comment, null);
    }

    public List<Comment> getAllComments() {
        //Select * from comments
        List<Comment> comments = new ArrayList<Comment>();
        //Fetching the results of query into cursor
        Cursor cursor = database.query(MySQLiteHelper.TABLE_ITEMS, allColumnsItems, null, null, null, null, null);
        //Move to front of cursor
        cursor.moveToFirst();
        //Iterate through cursor
        while(!cursor.isAfterLast()) {
            Comment comment = cursorToComment(cursor);
            //Add results to arraylist
            comments.add(comment);
            cursor.moveToNext();

        }
        cursor.close();
        return comments;
    }

    public Comment cursorToComment(Cursor cursor) {
        Comment comment = new Comment();
        comment.setId(cursor.getLong(0));
        comment.setComment(cursor.getString(1));
        return comment;
    }

}

我正在努力找出我的错误在哪里。我的约束应该都是有效的?

【问题讨论】:

    标签: java android sqlite


    【解决方案1】:

    查看您的代码后,我可以假设您正在尝试在表格中使用唯一的项目名称,对吧?如果是这样,那么这个错误是显而易见的。在您的表items 中,您将name 作为主键,并且您每次都尝试插入TEST。表中已经存在。

    有 3 种方法可以解决这个问题。

    1. name 列中删除主键约束。但是,您可以在此之后输入重复的名称。
    2. 不要在测试时对值进行硬编码。生成唯一名称并插入它。如下所示

      int index = new Random().nextInt(3);
      comment = datasource.createComment("TEST" + index, (float) 12.30);
      
      // concatenate `index` variable to `TEST` that's it.
      
    3. 从用户 (GUI) 获取输入并将其插入到表格中。

    PSnextInt(3) 方法将返回从 0 到 2 的数字。当您测试代码时,您会得到重复的名称。因此,在使用随机数生成器时要小心。我想推荐我的最后一点。

    【讨论】:

    • 添加索引似乎已修复它。我完全忽略了这个事实。谢谢!如此简单的修复。
    • 正如其他答案中所建议的,请将带有主键的_id 列添加到您的表中并自动递增。执行DELETEUPDATESELECT 等操作会很有帮助。祝您编码愉快!
    • 谢谢!我打算将评论或“测试”部分作为用户的输入。
    【解决方案2】:

    在这里,您尝试使用文本主键创建表,理想情况下应该是自动增量。这就是它的返回约束失败的原因。

     private static final String TABLE_CREATE_ITEMS = "create table "
            + TABLE_ITEMS + "( " + ITEMS_COLUMN_NAME + " text primary key, "
            + ITEMS_PRICE + " real not null );";
    

    应该是

    CREATE TABLE TableName(
    _id     INTEGER PRIMARY KEY,      -- autoincrementing, for Android
    NAME    TEXT,
    [...]);
    

    你可以参考 Inserting values to SQLite table in Android

    【讨论】:

    • 啊,是的,我确实忘记了_id,但我仍然遇到同样的错误。
    【解决方案3】:

    请试试这个:

    public void onClick (View v) {
    @SuppressWarnings("unchecked")
        //Load up the current values in the adapter into this adapter object
                ArrayAdapter<Comment> adapter = (ArrayAdapter<Comment>)getListAdapter();
        //Set comment to null
        Comment comment = new Comment(); //have to change this from null to new Comment();
        //Check to see which button was pressed
        switch (v.getId()) {
            case R.id.insert:
                String[] option = new String[] {"One", "Two", "Three"};
                int index = new Random().nextInt(3);
                //When inserting comment you just have to pass value
                comment = datasource.createComment("TEST", (float) 12.30);
                adapter.add(comment); //Adding to listview
                break;
            case R.id.delete:
                if(getListAdapter().getCount() > 0) {
                    comment = (Comment)getListAdapter().getItem(0);
                    adapter.remove(comment);//removing from listview
                    datasource.deleteComment(comment); //delete from db.
                }
                break;
        }
        //Updating the adapter
        adapter.notifyDataSetChanged();
    }
    

    还有你的SQLiteOpenHelper

    public class MySQLiteHelper extends SQLiteOpenHelper {
    
        //Creating the items table
        public  static final String TABLE_ITEMS = "items";
        public  static final String ITEMS_COLUMN_NAME = "name";
        public  static final String ITEMS_PRICE = "price";
    
    
    
        private static final String DATABASE_NAME  = "menu";
        private static final int DATABASE_VERSION  = 1;
    
        // create table comments(
        //   _id integer primary key autoincrement,
        //   comment text not null );
         private static final String TABLE_CREATE_ITEMS = "CREATE TABLE IF NOT EXISTS " + TABLE_ITEMS + "("
                + ITEMS_AUTO_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," //this is just _id
                + ITEMS_COLUMN_NAME + " VARCHAR,"
                + ITEMS_PRICE + " FLOAT)";
    
        public MySQLiteHelper( Context context ) {
            super( context, DATABASE_NAME, null, DATABASE_VERSION );
        }
    
        @Override
        public void onCreate( SQLiteDatabase database ) {
            //Create the items table
            database.execSQL( TABLE_CREATE_ITEMS );
            //Create the combos table
            //database.execSQL(TABLE_CREATE_COMBO);
        }
    
        @Override
        public void onUpgrade( SQLiteDatabase db, int oldVersion, int newVersion ) {
            Log.w( MySQLiteHelper.class.getName( ), "Upgrading database from version "
                    + oldVersion + " to " + newVersion + ", which will destroy all old data" );
            db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_ITEMS );
            //db.execSQL( "DROP TABLE IF EXISTS" + TABLE_CREATE_COMBO );
            onCreate( db );
        }
    }
    

    【讨论】:

    • 我已经在我的 createComment 方法中使用 ContentViews。基本上我所做的就是打包这些值,然后运行 ​​SQliteDatabase 命令,对吧?
    • 请试试这个。根据阅读stackoverflow.com/questions/8117685/… .. 有一个空
    • 另外,请删除您的onUpgrade() 代码。如果您更改数据库版本,它将删除数据库(即使您的表上有数据)
    • 不幸的是,我遇到了同样的错误。我也不完全确定如何在 android studio 上正确调试。
    • 尝试检查logcat并点击蓝色链接
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-07-18
    • 2022-06-12
    • 2016-11-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多