【问题标题】:Deleting Only One Row in SQLite Using ContentProvider使用 ContentProvider 仅删除 SQLite 中的一行
【发布时间】:2017-05-17 03:07:00
【问题描述】:

我正在尝试使用内容提供程序从 SQLite 数据库中仅删除一行,但我的代码删除了所有行。这是我正在做的事情:

我正在传递这个 uri:

content://appfactory.app.dehleezcafe/category/1

其中“类别”是表名,“1”是要删除的记录。

这是我在某处调用的删除代码:

 // Delete category
        this.getContentResolver().delete(
                contentURI,
                null,
                null
        );

contentURI 等于传递的 uri。

ContentProvider 类中的 delete 方法发生了什么:

rowsDeleted = db.delete(CategoryEntry.TABLE_NAME, selection, selectionArgs);

这将删除所有行而不是第“1”行??这不是我想要的。我很感激任何建议。

这是我的合同:

public static final String CONTENT_AUTHORITY = "appfactory.app.dehleezcafe";

public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);

public static final String PATH_CATEGORY = "category";
public static final String PATH_ITEM = "item";

Category BaseColumns 类:

public static final class CategoryEntry implements BaseColumns {

    public static final String TABLE_NAME = "category";

    public static final String COLUMN_CATEGORY_NAME  = "name";

    public static final Uri CONTENT_URI =
            BASE_CONTENT_URI.buildUpon().appendPath(PATH_CATEGORY).build();

    public static final String CONTENT_TYPE =
            ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_CATEGORY;

    public static Uri buildCategoryUri(long id) {
        return ContentUris.withAppendedId(CONTENT_URI, id);

    }
}

Item BaseColumns 类

 public static final class ItemEntry implements BaseColumns {

    public static final String TABLE_NAME = "item";

    public static final String COLUMN_TITLE = "title";
    public static final String COLUMN_DESCRIPTION = "description";
    public static final String COLUMN_PRICE = "price";
    public static final String COLUMN_PHOTO = "photo";
    // Column with the foreign key into the category table.
    public static final String COLUMN_CATEGORY_KEY = "category_id";

    public static final Uri CONTENT_URI =
            BASE_CONTENT_URI.buildUpon().appendPath(PATH_ITEM).build();

    public static final String CONTENT_TYPE =
            ContentResolver.CURSOR_DIR_BASE_TYPE + "/" + CONTENT_AUTHORITY + "/" + PATH_ITEM;

    public static Uri buildItemUri(long id) {
        return ContentUris.withAppendedId(CONTENT_URI, id);

    }

创建语句:

 // Category table create statement
final String SQL_CREATE_CATEGORY_TABLE = "CREATE TABLE " + CategoryEntry.TABLE_NAME + " (" +

        CategoryEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
        CategoryEntry.COLUMN_CATEGORY_NAME + " TEXT NOT NULL, " +
        " )";

 // Item table create statement
final String SQL_CREATE_ITEM_TABLE = "CREATE TABLE " + ItemEntry.TABLE_NAME + " (" +

        ItemEntry._ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
        // the ID of the category entry associated with this item data
        ItemEntry.COLUMN_CATEGORY_KEY + " INTEGER, " +
        ItemEntry.COLUMN_NAME + " TEXT NOT NULL, " +
        ItemEntry.COLUMN_DESCRIPTION + " TEXT NOT NULL, " +
        ItemEntry.COLUMN_PRICE + " TEXT NOT NULL, " +
        ItemEntry.COLUMN_PHOTO + " BLOB, " +

        // Set up the category column as a foreign key to category table.
        " FOREIGN KEY (" + ItemEntry.COLUMN_CATEGORY_KEY + ") REFERENCES " +
        CategoryEntry.TABLE_NAME + " (" + CategoryEntry._ID + ") " +
        " )";

// Constructor
public MenuSQLiteHelper(Context context) {
    super(context, DATABASE_NAME, null, DATABASE_VERSION);
}

内容提供者中的删除方法:

// Delete Method
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
    // Student: Start by getting a writable database
    final SQLiteDatabase db = menuDbHelper.getWritableDatabase();

    // Student: Use the uriMatcher to match the WEATHER and LOCATION URI's we are going to
    // handle.  If it doesn't match these, throw an UnsupportedOperationException.
    final int matchVal =  uriMatcher.match(uri);
    int rowsDeleted = 0;

    // This makes delete all rows return the number of rows deleted
    if(selection == null)
        selection = "1";

    switch (matchVal) {
        case ITEM:
            rowsDeleted = db.delete(
                    MenuContract.ItemEntry.TABLE_NAME, selection, selectionArgs);
            break;

        case CATEGORY:
            rowsDeleted = db.delete(
                    MenuContract.CategoryEntry.TABLE_NAME, selection, selectionArgs);
            break;

        case ITEM_WITH_CATEGORY:
            rowsDeleted = db.delete(CategoryEntry.TABLE_NAME, selection, selectionArgs);
            break;

        default:
            throw new UnsupportedOperationException("Unknown Uri: " + uri);

    }
    // A null value deletes all rows.
    if(rowsDeleted != 0 ) {
        getContext().getContentResolver().notifyChange(uri, null);
    }

    // Return the actual rows deleted
    return rowsDeleted;
}

我可以识别案例,但仅删除一行没有成功。

编辑

奇怪的是,我可以使用以下代码从“item”表中删除特定列而没有问题:

  // Delete items of a category
        String[] selctionArg = {String.valueOf(id)};

        this.getContentResolver().delete(
                ItemEntry.CONTENT_URI,
                ItemEntry.COLUMN_CATEGORY_KEY+"=?",
                selctionArg
                );

对“类别”表使用相同的代码不会删除任何内容,并且使用之前的代码会删除所有行而不是特定行

【问题讨论】:

    标签: android sqlite android-contentprovider


    【解决方案1】:

    我有一个解决方案给你,试试吧!

    请注意,我已对 CATEGORY 案例进行了更正。并且不要忘记将 _id 替换为您的列名。

    // Delete Method
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // Student: Start by getting a writable database
        final SQLiteDatabase db = menuDbHelper.getWritableDatabase();
    
        // Student: Use the uriMatcher to match the WEATHER and LOCATION URI's we are going to
        // handle.  If it doesn't match these, throw an UnsupportedOperationException.
        final int matchVal =  uriMatcher.match(uri);
        int rowsDeleted = 0;
    
        // This makes delete all rows return the number of rows deleted
        if(selection == null)
            selection = "1";
    
        switch (matchVal) {
            case ITEM:
                rowsDeleted = db.delete(
                        MenuContract.ItemEntry.TABLE_NAME, selection, selectionArgs);
                break;
    
            case CATEGORY:
                String segmentnew = uri.getPathSegments().get(1);
    
                if (TextUtils.isEmpty(selection)) {
                    selection = "_id=" + segmentnew;
                } else {
                    selection = "_id=" + segmentnew + " AND (" + selection + ")";
                }
    
                rowsDeleted = db.delete(
                        MenuContract.CategoryEntry.TABLE_NAME, selection, selectionArgs);
                break;
    
            case ITEM_WITH_CATEGORY:
                rowsDeleted = db.delete(CategoryEntry.TABLE_NAME, selection, selectionArgs);
                break;
    
            default:
                throw new UnsupportedOperationException("Unknown Uri: " + uri);
    
        }
        // A null value deletes all rows.
        if(rowsDeleted != 0 ) {
            getContext().getContentResolver().notifyChange(uri, null);
        }
    
        // Return the actual rows deleted
        return rowsDeleted;
    }
    

    希望这对你有用!

    【讨论】:

    • 感谢,我替换了您建议的代码并添加了 CategoryEntry._ID + "=" 代替 "_id=",但现在它并没有像什么都没发生一样删除任何东西。
    • @fullMoon 你得到了正确的segmentnew 值吗?您是否调试并检查了值?
    • 是的,segmentnew 正在返回我想正确删除的行位置,我不知道为什么它没有删除任何内容,并且总是为“rowsDeleted”返回 0
    【解决方案2】:

    试试这个方法很有用

    SQLiteDatabase db = this.getWritableDatabase();
    int x = db.delete(MenuContract.ItemEntry.TABLE_NAME,
            MenuContract.ItemEntry.ITEM_ID + " = ?",
            new String[]{item_id});
    System.out.println("number of rows deleted"+x);
    db.close();         
    

    【讨论】:

    • 谢谢哥们,它现在没有用,它没有删除任何东西,好像我没有按删除按钮
    【解决方案3】:

    this.getContentResolver().delete(CategoryEntry.CONTENT_URI,CategoryEntry._I‌​D + " = ?", new String[]{String.valueOf(id)});

    将此与您的原始代码一起使用

    【讨论】:

    • 对不起使用CategoryEntry._ID
    • 你是从uri.getpathsegments().get(1)得到categoryId吗?
    • 我使用 CategoryEntry._ID 并且是 categoryId 返回我要删除的正确行
    • this.getContentResolver().delete(contentURI,CategoryEntry._ID + " = ?", new String[]{String.valueOf(id)}); 将此与您的原始代码一起使用
    • 谢谢,我使用了它,但仍然没有从类别表中删除任何行。我可以毫无问题地从项目表中删除特定项目。请参阅问题末尾的编辑。太奇怪了,我对两者都使用了相同的代码并相应地对其进行了更改,但它在一个表中删除,而不在另一个表中删除。
    【解决方案4】:

    感谢大家。我能够解决这个问题。问题是我在列表视图中传递行的位置,考虑到它与 SQLite 数据库中行的 _id 相同。仅当我们第一次创建列表视图行并将它们存储在数据库中时才如此,因为它们匹配。但是,当我们删除行时,列表视图行的位置会更改它们的值,并且不再有效地作为选择条件中 sqlite 中的项目的 _id 传递,因为 sqlite 项目的 _id 保持不变并且不受列表视图中位置更改的影响.为了解决这个问题,我需要传递单击项目的光标并从光标中提取项目的 _id。 为简单起见,假设我希望在单击时删除一个项目:

    listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView adapterView, View view, int position, long id) {
    
                Cursor cursor = (Cursor) adapterView.getItemAtPosition(position);
    

    在类别片段的某处,我正在为类别列声明常量:

    // These indices are tied to CATEGORY_COLUMNS.  If FORECAST_COLUMNS changes, these
    // must change.
    static final int COL_CATEGORY_ID = 0;
    

    然后我可以将该光标传递到任何地方以提取您要删除的项目的_id:

    @Override
    public void deleteItem(Uri contentURI, Cursor cursor) {
    
        long id = cursor.getLong(CategoryFragment.COL_CATEGORY_ID);
    
        // Delete items of a category
        String[] selctionArg = {String.valueOf(id)};
    
        // Delete category
        getContentResolver().delete(
                MenuContract.CategoryEntry.CONTENT_URI,
                MenuContract.CategoryEntry._ID + "=?",
                selctionArg
        );
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多