問題:在第一次查詢之前,我似乎無法讓匯入的資料庫在 Android Room 中失敗?我想要try/catch并驗證一個資料庫,但在第一次查詢之前我沒有成功捕獲它。我一直認為 Android Room 在instance創建時驗證了資料庫并針對模式進行構建,但顯然不是。所以資料庫在第一次查詢時失敗。
我正在嘗試做的事情:這個應用程式管理可以在用戶之間共享的多個資料庫。因此可以匯入或匯出資料庫。我懷疑在某些時候,有人會嘗試匯入錯誤的資料庫和/或結構,或者做一些事情導致它失敗。我正在嘗試在instance/構建資料庫時或更快地捕獲故障。
我試過的:我在第一個實體創建時有一個try/catch/finally塊,但它只在第一次查詢時失敗......然后它注意到一個表或列丟失了。如果可能的話,我想早點抓住它。我已經查看了這些RoomDatabase方法,但除了讓它中斷之外,沒有什么特別適用于我看到的驗證。
uj5u.com熱心網友回復:
我一直認為 Android Room 在實體創建時驗證了資料庫并針對模式進行構建,但顯然不是。
資料庫驗證是開放程序的一部分,在您實際嘗試訪問資料庫之前不會發生,而不是在獲取實體時。
在第一次查詢之前,我似乎無法讓匯入的資料庫在 Android Room 中失敗?
獲取實體后,您可以通過實體的 openHelper 使用 getWritableDatabase 或 getReadableDatabase 獲取(或嘗試獲取)SupportSQLiteDatabase 來強制打開。
例如
(科特林)
db = TheDatabase.getInstance(this)
try {
val supportDB = db.openHelper.writableDatabase
}
catch(e: Exception) {
....
}
(爪哇)
db = TheDatabase.getInstance(this);
try {
SupportSQLiteDatabase supportDB = db.getOpenHelper().getWritableDatabase();
}
catch (Exception e) {
....
}
uj5u.com熱心網友回復:
替代方案 - 自我驗證
您也可以進行自己的驗證,從而避免例外(如果驗證足夠簡單)。您也可以進行更正,從而允許可能的輕微違規行為是可以接受的。
在獲取實際實體之前,您可以獲取根據 Room 創建的驗證實體(不同的資料庫名稱),然后自己比較模式。
這是一個示例,旨在通過創建具有不同表名(nottablex 而不是 tableX)的真實資料庫來檢測表丟失。
TableX物體:-
@Entity
class TableX {
@PrimaryKey
Long id=null;
String name;
String other;
}
示例中不需要 No Dao。
TheDatabase帶有get 實體方法,一個用于正常,另一個用于獲取另一個(驗證(用于模式比較的空模型))資料庫,但作為 SQLiteDatabase。
@Database(entities = {TableX.class},version = 1)
abstract class TheDatabase extends RoomDatabase {
private static volatile TheDatabase instance = null;
private static volatile TheDatabase validationInstance = null;
static TheDatabase getInstance(Context context, String databaseName) {
if (instance == null ) {
instance = Room.databaseBuilder(context,TheDatabase.class,databaseName)
.allowMainThreadQueries()
.build();
}
return instance;
}
static SQLiteDatabase getValidationInstance(Context context, String databaseName) {
// Delete DB if it exists
if (context.getDatabasePath(databaseName).exists()) {
context.getDatabasePath(databaseName).delete();
}
// Create database and close it
TheDatabase db = Room.databaseBuilder(context,TheDatabase.class,databaseName)
.allowMainThreadQueries()
.build();
db.getOpenHelper().getWritableDatabase();
db.close();
return SQLiteDatabase.openDatabase(context.getDatabasePath(databaseName).getPath(),null,SQLiteDatabase.OPEN_READWRITE);
}
}
- 請注意,這會強制 open 創建模型/驗證資料庫(否??則 openDatabase 將失敗)。
最后是演示MainActivity,它創建了一個無效的資料庫,然后繼續進行簡單的驗證(只需檢查預期的表是否存在)。如果房間期望的表存在,則僅打開(在示例的情況下從不)資料庫。
public class MainActivity extends AppCompatActivity {
public static final String DATABASE_NAME = "the_database.db";
public static final String VALIDATION_DATABASE_NAME = DATABASE_NAME "_validation";
public static final String TAG = "DBVALIDATION";
TheDatabase db;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
createIncorrectDatabase(this,DATABASE_NAME);
if (validateDatabase(VALIDATION_DATABASE_NAME,DATABASE_NAME) < 0) {
Log.d(TAG,"DATABASE " DATABASE_NAME " does mot match model.");
} else {
/* Database validated OK so use it */
db = TheDatabase.getInstance(this,DATABASE_NAME);
}
}
/* Purposefully create invalid database */
private void createIncorrectDatabase(Context context, String databaseName) {
File dbfile = context.getDatabasePath(databaseName);
if (!dbfile.exists()) {
dbfile.getParentFile().mkdirs();
}
SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(context.getDatabasePath(databaseName),null);
db.execSQL("CREATE TABLE IF NOT EXISTS nottablex(id INTEGER PRIMARY KEY,name TEXT)");
db.close();
}
@SuppressLint("Range")
private long validateDatabase(String modelDatabase, String actualDatabase) {
String sqlite_master = "sqlite_master";
/* Want to skip room_master_table and sqlite tables susch as sqlite_sequence */
/* in this example only checking tables to show the basic technique */
String wherecluase = "name NOT LIKE 'sqlite_%' AND name NOT LIKE 'room_%' AND type = 'table'";
long rv = 0;
/* Get the model/validation database */
SQLiteDatabase modelDB = TheDatabase.getValidationInstance(this,modelDatabase);
/* Only need to check if the database exists as otherwise it will be created according to Room */
if (this.getDatabasePath(actualDatabase).exists()) {
/* Open as an SQLiteDatabase so no Room open to throw an exception */
SQLiteDatabase actualDB = SQLiteDatabase.openDatabase(this.getDatabasePath(actualDatabase).getAbsolutePath(),null,SQLiteDatabase.OPEN_READWRITE);
/* Get the tables expected from the model Room database */
Cursor modelTableNames = modelDB.query(sqlite_master,null,wherecluase,null,null,null,null);
Cursor actualTableNames = null; /* prepare Cursor */
/* Loop through the tables names in the model checking if they exist */
while (modelTableNames.moveToNext()) {
/* See if the expected table exists */
actualTableNames = actualDB.query(sqlite_master,null,"name=?",new String[]{modelTableNames.getString(modelTableNames.getColumnIndex("name"))},null,null,null);
if (!actualTableNames.moveToFirst()) {
Log.d(TAG,"Table " modelTableNames.getString(modelTableNames.getColumnIndex("name")) " not found.");
rv = rv -1; /* Table not found so decrement rv to indicate number not found */
}
}
/* Close the actualTableNames Cursor if it was used */
if (actualTableNames != null) {
actualTableNames.close();
}
/* Close the modelTableNames Cursor */
modelTableNames.close();
/* Close the actual database so Room can use it (comment out to show results in database Inspector)*/
actualDB.close();
} else {
Log.d(TAG,"Actual Database " actualDatabase " does not exist. No validation required as it would be created");
}
/* Close and delete the model database (comment out to show results in database Inspector)*/
modelDB.close();
this.getDatabasePath(modelDatabase).delete();
return rv;
}
}
結果
日志包括:-
D/DBVALIDATION: Table TableX not found.
D/DBVALIDATION: DATABASE the_database.db does mot match model.
繞過關閉和模型洗掉上述資料庫是: -

- 請注意,在這個簡單的示例中,Room 實際上會創建 TableX 表,而不是因例外而失敗。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/412266.html
標籤:
下一篇:如何填充已填充關系的關系?
