gho*_*osh 5 android auto-increment android-sqlite android-room
我正在使用 Room 来保存数据。
我有一个实体,它有一个模拟票证系统的自动生成(自动生成)主键。
在每个应用程序运行时,我需要这个键从 0 开始。
实体:
@Entity
public class SequenceAction {
@PrimaryKey(autoGenerate = true)
private Integer sequenceId;
private String actionType;
private String extraInfo;
//getters & setters
}
Run Code Online (Sandbox Code Playgroud)
初始化:
// init sequenceAction object
// run with executor(sequenceId is automatically set on insert to table):
AppDatabase.getInstance(getContext()).sequenceActionDao().save(sequenceAction);
Run Code Online (Sandbox Code Playgroud)
我尝试过的事情:
我AppDatabase.getInstance(getApplicationContext()).clearAllTables(); 过去常常在退出时清除表,但这不会重置键起始索引,而是从上次运行时停止的位置开始。
我还没有找到使用 Room 执行此操作的方法,因此我正在尝试将 SimpleSQLiteQuery 传递给 Dao 中的 RawQuery 方法:
//Dao
@RawQuery()
Integer init(SimpleSQLiteQuery query);
//Passed query
new SimpleSQLiteQuery("...query...");
Run Code Online (Sandbox Code Playgroud)
我试过下一个查询:
"ALTER TABLE SequenceAction AUTO_INCREMENT = 0"我收到一个错误(我用“AUTOINCREMENT”试过这个,同样的错误):
android.database.sqlite.SQLiteException:在“AUTO_INCREMENT”附近:语法错误(代码 1):,编译时:ALTER TABLE SequenceAction AUTO_INCREMENT = 0
可能是因为,正如此问题/答案所述,SQLite 中没有自动增量关键字,而是声明为 INTEGER PRIMARY KEY 的列将自动自动增量。
"delete from sqlite_sequence where name='SequenceAction'"没有错误,但索引也不会重置。
正如这里所建议的:
"UPDATE SQLITE_SEQUENCE SET seq = -1 WHERE name = 'SequenceAction'"
没有错误,但没有效果。
"TRUNCATE TABLE 'SequenceAction';"错误(可能是因为SQLite 不支持 TRUNCATE 命令):
android.database.sqlite.SQLiteException:在“TRUNCATE”附近:语法错误(代码1):,编译时:TRUNCATE TABLE 'SequenceAction';
DELETE FROM SequenceAction没有错误,没有影响。
\n\n\n但是,为了在退出时清除表,这不会重置键\n起始索引,而是从上次运行时停止的位置开始。
\n
....
\n\n\n\n\n"delete from sqlite_sequence where name=\'Sequence Action\'" 没有错误\n但是,索引也没有重置。
\n
您必须删除SequenceAction表中的所有行并从 sqlite_sequence 中删除相应的行。
\n\n也就是说,当使用 AUTOINCRMENT 关键字时,会使用不同的算法。这大致如下:-
\n\n查找 \n - a) sqlite_sequence 编号中表的值存储和\n - b) 最高 rowid 值中的最高值
\n\n另一种方法是不使用AUTOINCREMENT关键字,而只使用关键字?? INTEGER PRIMARY KEY(其中 ?? 代表列名称)。
您仍然会有一个唯一的 id,它是rowidcoulmn 的别名,但不能保证它总是会增加。AUTOINCREMENT确实保证唯一 id 递增,但不保证单调递增唯一 rowid。
\n\n\n在每次运行应用程序时,我都需要这个键从 0 开始。
\n
然而,SQLite 会将第一个值设置为 1 而不是 0。
\n\n下面的代码确实有效,正如您在 AUTOINCRMENT 中看到的那样(尽管有点破解):-
\n\nDROP TABLE IF EXISTS SequenceAction;\nDROP TRIGGER IF EXISTS use_zero_as_first_sequence;\nCREATE TABLE IF NOT EXISTS SequenceAction (id INTEGER PRIMARY KEY AUTOINCREMENT, otherdata TEXT);\nCREATE TRIGGER IF NOT EXISTS use_zero_as_first_sequence AFTER INSERT ON SequenceAction\n BEGIN \n UPDATE SequenceAction SET id = id - 1 WHERE id = new.id;\n END\n;\nINSERT INTO SequenceAction VALUES(null,\'TEST1\'),(null,\'TEST2\'),(null,\'TEST3\');\nSELECT * FROM SequenceAction;\n-- RESET and RESTART FROM 0\nDELETE FROM SequenceAction;\nDELETE FROM sqlite_sequence WHERE name = \'SequenceAction\';\nINSERT INTO SequenceAction VALUES(null,\'TEST4\'),(null,\'TEST5\'),(null,\'TEST6\');\nSELECT * FROM SequenceAction\nRun Code Online (Sandbox Code Playgroud)\n\n这导致:-
\n\n第一个查询返回:-
\n\n\n\n第二次返回:-
\n\n\n\n所以本质上你想要:-
\n\nDELETE FROM SequenceAction;\nDELETE FROM sqlite_sequence WHERE name = \'SequenceAction\';\nRun Code Online (Sandbox Code Playgroud)\n\n如果您希望编号从 0 而不是 1 开始,还可以使用触发器。
\n\n或者,如果您取消了自动增量,那么您可以使用稍微改变的触发器:-
\n\nCREATE TRIGGER IF NOT EXISTS use_zero_as_first_sequence \n AFTER INSERT ON SequenceAction \n WHEN (SELECT count() FROM SequenceAction) = 1\n BEGIN \n UPDATE SequenceAction SET id = 0;\n END\n;\nRun Code Online (Sandbox Code Playgroud)\n\n然后只需从 SequenceAction 表中删除所有行即可重置编号。
\n\n根据您的代码以及上面的示例,以下方法似乎有效:-
\n\nprivate void resetSequenceAction() {\n SQLiteDatabase dbx;\n String sqlite_sequence_table = "sqlite_sequence";\n long initial_sacount;\n long post_sacount;\n long initial_ssn =0;\n long post_ssn = 0;\n Cursor csr;\n\n /*\n Need to Create Database and table if it doesn\'t exist\n */\n File f = this.getDatabasePath(TestDatabase.DBNAME);\n if (!f.exists()) {\n File d = new File(this.getDatabasePath(TestDatabase.DBNAME).getParent());\n d.mkdirs();\n dbx = SQLiteDatabase.openOrCreateDatabase(f,null);\n String crtsql = "CREATE TABLE IF NOT EXISTS " + SequenceAction.tablename + "(" +\n SequenceAction.id_column + " INTEGER PRIMARY KEY AUTOINCREMENT," +\n SequenceAction.actionType_column + " TEXT," +\n SequenceAction.extraInfo_column + " TEXT" +\n ")";\n dbx.execSQL(crtsql);\n /*\n Might as well create the Trigger as well\n */\n String triggerSql = "CREATE TRIGGER IF NOT EXISTS user_zero_as_first_rowid AFTER INSERT ON " +\n SequenceAction.tablename +\n " BEGIN " +\n " UPDATE " + SequenceAction.tablename +\n " SET " +\n SequenceAction.id_column + " = " + SequenceAction.id_column + " - 1 " +\n " WHERE " + SequenceAction.id_column + " = new." + SequenceAction.id_column + ";" +\n " END ";\n dbx.execSQL(triggerSql);\n\n } else {\n dbx = SQLiteDatabase.openDatabase(this.getDatabasePath(TestDatabase.DBNAME).getPath(),null, Context.MODE_PRIVATE);\n }\n\n /*\n Add trigger to set id\'s to 1 less than they were set to\n */\n initial_sacount = DatabaseUtils.queryNumEntries(dbx,SequenceAction.tablename);\n /*\n Delete all the rows at startup\n */\n String deleteAllSequenceIdRowsSql = "DELETE FROM " + SequenceAction.tablename;\n dbx.execSQL(deleteAllSequenceIdRowsSql);\n post_sacount = DatabaseUtils.queryNumEntries(dbx,SequenceAction.tablename);\n /*\n delete the sequence row from the sqlite_sequence table\n */\n csr = dbx.query(sqlite_sequence_table,\n new String[]{"seq"},"name=?",\n new String[]{SequenceAction.tablename},\n null,null,null\n );\n if (csr.moveToFirst()) {\n initial_ssn = csr.getLong(csr.getColumnIndex("seq"));\n }\n String deleteSqlLiteSequenceRow = "DELETE FROM " +\n sqlite_sequence_table +\n " WHERE name = \'" + SequenceAction.tablename + "\'";\n dbx.execSQL(deleteSqlLiteSequenceRow);\n csr = dbx.query(\n sqlite_sequence_table,\n new String[]{"seq"},\n "name=?",\n new String[]{SequenceAction.tablename},\n null,null,null\n );\n if (csr.moveToFirst()) {\n post_ssn = csr.getLong(csr.getColumnIndex("seq"));\n }\n csr.close();\n Log.d("SEQACTSTATS",\n "Initial Rowcount=" + String.valueOf(initial_sacount) +\n " Initial Seq#=" + String.valueOf(initial_ssn) +\n " Post Delete Rowcount =" + String.valueOf(post_sacount) +\n " Post Delete Seq#=" + String.valueOf(post_ssn)\n );\n dbx.close();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n初始运行的结果(即不存在数据库):-
\n\nD/SEQACTSTATS: Initial Rowcount=0 Initial Seq#=0 Post Delete Rowcount =0 Post Delete Seq#=0\nRun Code Online (Sandbox Code Playgroud)\n\n从后续运行(添加 40 行后):-
\n\nD/SEQACTSTATS: Initial Rowcount=40 Initial Seq#=40 Post Delete Rowcount =0 Post Delete Seq#=0\nRun Code Online (Sandbox Code Playgroud)\n\n添加一个方法来列出所有行,如下所示:-
\n\nprivate void listAllRows() {\n new Thread(new Runnable() {\n @Override\n public void run() {\n salist = mTestDB.SequenceActionDaoAccess().getAll();\n getSequenceActionList(salist);\n }\n }).start();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n随着 :-
\n\n@Override\npublic void getSequenceActionList(List<SequenceAction> sequenceActionList) {\n for (SequenceAction sa: sequenceActionList) {\n Log.d("SA","ID=" + String.valueOf(sa.getSequenceId()) + " AT=" + sa.getActionType() + " EI=" + sa.getExtraInfo());\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n结果(第一行即ID=0 AT=X0 EI=Y0第一行的ID列为0):-
06-17 02:56:47.867 5526-5554/rt_mjt.roomtest D/SA: ID=0 AT=X0 EI=Y0\n ID=1 AT=X0 EI=Y0\n ID=2 AT=X0 EI=Y0\n ID=3 AT=X0 EI=Y0\n ID=4 AT=X1 EI=Y1\n ID=5 AT=X1 EI=Y1\n ID=6 AT=X1 EI=Y1\n ID=7 AT=X1 EI=Y1\n06-17 02:56:47.868 5526-5554/rt_mjt.roomtest D/SA: ID=8 AT=X2 EI=Y2\n ID=9 AT=X2 EI=Y2\n ID=10 AT=X2 EI=Y2\n ID=11 AT=X2 EI=Y2\n ID=12 AT=X3 EI=Y3\n ID=13 AT=X3 EI=Y3\n ID=14 AT=X3 EI=Y3\n ID=15 AT=X3 EI=Y3\n ID=16 AT=X4 EI=Y4\n06-17 02:56:47.869 5526-5554/rt_mjt.roomtest D/SA: ID=17 AT=X4 EI=Y4\n ID=18 AT=X4 EI=Y4\n ID=19 AT=X4 EI=Y4\n ID=20 AT=X5 EI=Y5\n ID=21 AT=X5 EI=Y5\n ID=22 AT=X5 EI=Y5\n ID=23 AT=X5 EI=Y5\n ID=24 AT=X6 EI=Y6\n ID=25 AT=X6 EI=Y6\n ID=26 AT=X6 EI=Y6\n ID=27 AT=X6 EI=Y6\n06-17 02:56:47.870 5526-5554/rt_mjt.roomtest D/SA: ID=28 AT=X7 EI=Y7\n ID=29 AT=X7 EI=Y7\n ID=30 AT=X7 EI=Y7\n ID=31 AT=X7 EI=Y7\n ID=32 AT=X8 EI=Y8\n ID=33 AT=X8 EI=Y8\n ID=34 AT=X8 EI=Y8\n ID=35 AT=X8 EI=Y8\n ID=36 AT=X9 EI=Y9\n ID=37 AT=X9 EI=Y9\n ID=38 AT=X9 EI=Y9\n ID=39 AT=X9 EI=Y9\nRun Code Online (Sandbox Code Playgroud)\n\n使用的方法addSomeData是:-
private void addSomeData() {\n new Thread(new Runnable() {\n @Override\n public void run() {\n SequenceAction sa = new SequenceAction();\n for (int i=0; i < 10; i++) {\n sa.setSequenceId(0);\n sa.setActionType("X" + String.valueOf(i));\n sa.setExtraInfo("Y" + String.valueOf(i));\n mTestDB.SequenceActionDaoAccess().insertSingleRow(sa);\n }\n }\n }) .start();\n}\nRun Code Online (Sandbox Code Playgroud)\n\n\n\n\n“我相信你必须在 Room 之前进入...” - 你的意思是在实例化 Room 数据库之前执行\n 清除正在运行的索引的 SQL 吗?- 戈什
\n\n不一定,但在 Room\n 打开数据库之前,也就是在您尝试对其执行任何操作之前。\n 添加了调用代码(在 Overidden 活动的 onStart() 方法中)\n 在使用某些 Room Db 访问 addSomeData 之后立即调用。\xe2\x80\x93\n 麦克T
\n
下面是在 RoomDatabase 实例化之后、用于访问/打开数据库之前调用 resetSequenceAction 方法的示例(addSomeData 打开已实例化的数据库并插入 10 行):-
\n\n@Override\nprotected void onStart() {\n super.onStart();\n mTestDB = Room.databaseBuilder(this,TestDatabase.class,TestDatabase.DBNAME).build(); //<<<< Room DB instantiated\n resetSequenceAction(); //<<<< reset the sequence (adding trigger if needed)\n addSomeData(); // This will be the first access open\n addSomeData();\n addSomeData();\n addSomeData();\n listAllRows();\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
8356 次 |
| 最近记录: |