java - onCreate 按预期被调用。但表没有创建

标签 java android sqlite

所以我遇到了这个让我很烦恼的问题。我重写了扩展 SQLiteOpenHelper 的类的 onCreate 方法:

    @Override
public void onCreate(SQLiteDatabase db) {
    super.onCreate(db);
    final String createAccTableCmd = ("CREATE TABLE IF NOT EXISTS " + ACCOUNTS_TABLE_NAME + " ( " +
            ACCOUNT_KEY_ID + " INTEGER PRIMARY KEY ASC AUTOINCREMENT, " +
            ACCOUNT_KEY_NAME + " TEXT UNIQUE ON CONFLICT IGNORE NOT NULL ON CONFLICT IGNORE, " +
            ACCOUNT_KEY_SELECTED + " INTEGER NOT NULL ON CONFLICT IGNORE, " + //THIS IS IN MILLISECONDS
            "CHECK (" + ACCOUNT_KEY_SELECTED + " = 0 OR " + ACCOUNT_KEY_SELECTED + " = 1) ON CONFLICT IGNORE" +
            " ) ");
    final String oneAndOnlyOneSelectedAccInsertTriggerCmd = "CREATE TRIGGER " + ONE_AND_ONLY_ONE_SELECTED_TRIGGER_INSERT_NAME + " " +
            "AFTER INSERT ON " + ACCOUNTS_TABLE_NAME + " " +
            "FOR EACH ROW " +
            "BEGIN " +
            "DELETE FROM " + ACCOUNTS_TABLE_NAME + " WHERE " + ACCOUNT_KEY_ID + " = NEW." + ACCOUNT_KEY_ID + "; " +
            "END";
    final String oneAndOnlyOneSelectedUpdateTriggerCmd = "CREATE TRIGGER " + ONE_AND_ONLY_ONE_SELECTED_TRIGGER_UPDATE_NAME + " " +
            "AFTER UPDATE ON " + ACCOUNTS_TABLE_NAME + " " +
            "FOR EACH ROW " +
            "WHEN (SELECT(SUM(" + ACCOUNT_KEY_ID + ")) <> 1) " +
            "BEGIN " +
            "UPDATE " + ACCOUNTS_TABLE_NAME + " SET " + ACCOUNT_KEY_SELECTED + " = 0; " +
            "UPDATE " + ACCOUNTS_TABLE_NAME + " SET " + ACCOUNT_KEY_SELECTED + " = 1 WHERE " + ACCOUNT_KEY_ID + " = NEW." + ACCOUNT_KEY_ID + "; " +
            "END";
    synchronized (DB_LOCK) {
        db.beginTransaction();
        db.execSQL(createAccTableCmd);
        db.execSQL(oneAndOnlyOneSelectedAccInsertTriggerCmd);
        db.execSQL(oneAndOnlyOneSelectedUpdateTriggerCmd);
        addTableName(ACCOUNTS_TABLE_NAME);
        ContentValues cv = new ContentValues();
        cv.put(ACCOUNT_KEY_ID, 0);
        cv.put(ACCOUNT_KEY_NAME, "name");
        cv.put(ACCOUNT_KEY_SELECTED, 0);
        Log.d("debug", "-1 if error on insert: " + db.insert(ACCOUNTS_TABLE_NAME, "", cv));
        Log.d("debug", "Size: " + db.query(ACCOUNTS_TABLE_NAME, null, null, null, null, null, ACCOUNT_KEY_ID + " ASC").getCount());
        db.setTransactionSuccessful();
        db.endTransaction();
        LBackupAgent.requestBackup(mContext);
    }
    Log.d("debug", "Size after ending the transaction: " + db.query(ACCOUNTS_TABLE_NAME, null, null, null, null, null, ACCOUNT_KEY_ID + " ASC").getCount());
}

人们期望它的输出是:

  • 如果插入错误则为-1:0
  • Size: 0/* 或 1,如果 select 考虑了当前事务未提交的数据,这个我不确定 */
  • 交易结束后的大小:1

当实际输出恰好是:

  • 如果插入错误则为-1:0
  • 大小:0
  • 交易结束后的大小:0

怎么会插入成功但是选择返回0行呢? 我已经用 shell 检查了该表确实存在,但实际上它是空的,这可以通过以下事实来解释:在 onCreate() 完成之前,这些表似乎并不真正存在,这也证明了由插入命令。我是否应该猜测这是某种设计约束以确保 onCreate 只包括 CREATE TABLE、CREATE TRIGGER 和此类语句?如果我认为我的架构定义需要插入(情况就是如此)怎么办?

最佳答案

尝试插入一些虚拟值而不是下面的值:

ContentValues defaultAcc = mapAccountToStorable(defaultAccDataModel = new AccountListRecyclerAdapter.AccountDataModel(
                        LBudgetUtils.getInt(mContext, "default_account_id"),
                        LBudgetUtils
                                .getString(mContext, "default_account_name"),
                        mContext.getResources().getBoolean(
                                R.bool.default_account_selected)));

不要将 nullColumnHack 作为 null 发送,而是将其作为“”发送。即使值为空,它将确保在表中创建一行。

db.insert(ACCOUNTS_TABLE_NAME, "", defaultAcc)

尝试以下:

    db.beginTransaction();
    db.execSQL(createAccTableCmd);
    db.execSQL(oneAndOnlyOneSelectedAccInsertTriggerCmd);
    db.execSQL(oneAndOnlyOneSelectedUpdateTriggerCmd);
    db.setTransactionSuccessful();
    db.endTransaction();

    db.beginTransaction();
    addTableName(ACCOUNTS_TABLE_NAME);
    AccountListRecyclerAdapter.AccountDataModel defaultAccDataModel;
    ContentValues defaultAcc = mapAccountToStorable(defaultAccDataModel = new AccountListRecyclerAdapter.AccountDataModel(LBudgetUtils.getInt(mContext, "default_account_id"), LBudgetUtils.getString(mContext, "default_account_name"), mContext.getResources().getBoolean(R.bool.default_account_selected)));
    Log.d("debug", "-1 if error on insert: " + db.insert(ACCOUNTS_TABLE_NAME, null, defaultAcc));
    db.setTransactionSuccessful();
    db.endTransaction();


    Log.d("debug", "Size: " + db.query(ACCOUNTS_TABLE_NAME, null, null, null, null, null, ACCOUNT_KEY_ID + " ASC").getCount());

关于java - onCreate 按预期被调用。但表没有创建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25443680/

相关文章:

android - 如何在android中连接服务器数据库而不会丢失/失败?

java - 类不存在:终端中的Mapreduce程序

android - 如何突出显示 Recycler View 的选定项目?

java - 撤消 java mkdirs() 的效果

android - 如何在 Android 应用程序中使用自定义 Flash 播放器

Android Studio git checkout

android - Android 应用程序中的 SQLite-sync 同步框架

java - 从文件在 SD 卡上创建数据库

java - 如何将类名用作数据类型?

java - 如何防止直接 URL 访问 Android 应用程序中使用的文件?