【问题标题】:How to check if data is inserted in Room Database如何检查数据是否插入到房间数据库中
【发布时间】:2018-01-04 03:37:26
【问题描述】:

我在我的项目中使用来自新架构组件的房间数据库。 我正在通过 dao 添加一些数据,但是在尝试检索它时我没有得到它。您能否建议我如何检查插入是否成功?以下是帮助您理解问题的代码。

添加到数据库,我用调试器检查,这条语句执行成功。

appContext.db.rallyDAO().addVehicleListItem(vehicle)

插入后在此语句上从数据库中获取空值。

val v = appContext.db.rallyDAO().getVehicleListItem(it.vehicleID)

房间数据库

@Database(entities = arrayOf(Rally::class, Route::class, CheckPoints::class, Vehicles::class, VehicleListItem::class), version = 1)
abstract class TSDRoom: RoomDatabase() {
    public abstract fun rallyDAO():RallyDAO
}

DAO 内部

@Insert(onConflict = OnConflictStrategy.REPLACE)
    fun addVehicleListItem(vehicleListItem:VehicleListItem)

    @Query("select * from vehicles_submitted where vehicle_id LIKE :vehicleID")
    fun getVehicleListItem(vehicleID:String):VehicleListItem

VehicleListItem 实体

@Entity(tableName = "vehicles_submitted",
        foreignKeys = arrayOf(ForeignKey(entity = Rally::class,
                parentColumns = arrayOf("rally_id"),
                childColumns = arrayOf("rally_id"))))
class VehicleListItem {
    @PrimaryKey
    @ColumnInfo(name = "vehicle_id")
    @SerializedName("vehicle_id")
    var vehicleID : String = ""
    @ColumnInfo(name = "driver_id")
    @SerializedName("driver_id")
    var driverID : String = ""
    @ColumnInfo(name = "vehicle_name")
    @SerializedName("vehicle_name")
    var vehicleName : String = ""
    @ColumnInfo(name = "driver_name")
    @SerializedName("driver_name")
    var driverName : String = ""
    @ColumnInfo(name = "driver_email")
    @SerializedName("driver_email")
    var driverEmail : String = ""

    @ColumnInfo(name = "rally_id")
    @SerializedName("rally_id")
    var rallyID: String = ""

    @ColumnInfo(name = "is_passed")
    @SerializedName("is_passed")
    var isPassed = false

    @ColumnInfo(name = "passing_time")
    @SerializedName("passing_time")
    var passingTime:String=""
}

【问题讨论】:

    标签: android kotlin android-room


    【解决方案1】:

    问题出在线程中。 Room 不允许您在主线程中运行数据库查询。对 insert 方法的调用在 try-catch 块内,我忽略了异常。 我修好了,现在是这样的。

    doAsync {
                            val addedID = appContext.db.rallyDAO().addVehicleListItem(vehicle)
                            Logger.d("vehicle_lsit_item","Inserted ID $addedID")
            }
    

    另外,我查看了documentation,insert 方法可能返回一个 Long(或 List 的 Long,如果 List 传递给 insert)。我也改了insert的签名,这里是修改后的代码

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    fun addVehicleListItem(vehicleListItem:VehicleListItem):Long
    

    附:我将anko 用于doAsync

    【讨论】:

      【解决方案2】:

      您可以使用 Stetho 在 chrome 开发工具中查看您的数据库和共享首选项文件

      http://facebook.github.io/stetho/

      编辑:AS 现在有一个内置的数据库工具

      【讨论】:

        【解决方案3】:

        如果您没有访问权限问题,您可以考虑的一个选项是直接导航到设备的 sqlite 实例并直接在那里查询表。

        如果您使用与 Android Studio 或 root 手机集成的模拟器,您可以执行以下操作:

        adb root
        adb remount
        cd data/data/path/of/your/application/database
        sqlite3 mydb.db
        

        然后你就可以查询你的表了

        【讨论】:

        • 我在remount上遇到很多错误,可能都总结为ERROR: * Read-only file system
        【解决方案4】:

        您可以通过多种方式对其进行测试。

        1. 正如@Ege Kuzubasioglu 所说,您可以使用stetho 手动检查(需要对代码进行细微更改)。
        2. 将数据库文件从“data/data/yourpackage/databases/yourdatabase.db”拉到本地计算机,并使用任何应用程序读取数据库内的内容。我个人使用https://sqlitebrowser.org/。 可以使用 shell 命令或使用 android studio 中的“设备文件资源管理器”来拉取数据库文件。

        3. 编写TestCase 看看它是否有效。这是我的一个项目中的一个测试用例示例。

          // 我的 DAO 类中的代码

          @Insert(onConflict = OnConflictStrategy.REPLACE) public abstract Long[] insertPurchaseHistory(List MusicOrders);

        //我的测试用例 @测试 public void insertPurchaseHistoryTest() {

            // Read test data from "api-responses/music-purchase-history-response.json"
            InputStream inputStream = getClass().getClassLoader()
                    .getResourceAsStream("api-responses/music-purchase-history-response.json");
            // Write utility method to convert your stream to a string.
            String testData = FileManager.readFileFromStream(inputStream);
        
            // Convert test data to "musicOrdersResponse"
            MusicOrdersResponse musicOrdersResponse = new Gson().fromJson(testData,MusicOrdersResponse.class);
        
            // Insert inmateMusicOrders and get the list of
            Long[] rowsInserted = tracksDao.insertPurchaseHistory(musicOrdersResponse.getmusicOrders());
            assertThat(rowsInserted.length,Matchers.greaterThan(0));
        }
        

        【讨论】:

        • Room数据库操作没有回调吗?
        • #2 对我不起作用,即使我可以通过 DB 查询并清楚地看到有数据返回。 SQLiteBrowser 显示下载的数据库为空。
        【解决方案5】:

        您可以使用Android Debug Database 通过网络浏览器访问应用程序的数据库。 Android 调试数据库通过嵌入式 Web 服务器公开数据库。

        如下使用:

        1. 将其作为 debugImplementation 依赖项包含在您应用的 build.gradle 中,以便它仅包含在调试版本中,而不包含在发布版本中:

          debugImplementation 'com.amitshekhar.android:debug-db:1.0.3'
          
        2. 开始调试应用程序

        3. 嵌入式网络服务器自动启动并在日志中公布其地址和端口:

          D/DebugDB: Open http://XXX.XXX.X.XXX:8080 in your browser
          
        4. 如果您通过 USB 运行应用程序,请设置端口转发:

          adb forward tcp:8080 tcp:8080
          

          如果您不是通过 USB 运行应用程序,您的 Android 手机和工作站需要在同一个网络中,并且您的工作站应该能够 ping Android 手机。

        5. 最后,从浏览器的日志中打开链接。

        请注意,由于 Web 服务器在您的应用上下文中运行,因此无需 root 设备即可正常工作。

        【讨论】:

        • 很多人投了赞成票,也有很多人投了反对票,所以它似乎对某些人有效,而对其他人无效。向拒绝投票者请求帮助 - 你能解释一下你看到了什么错误或者你为什么不喜欢这种方法吗?
        【解决方案6】:

        关于插入有两种情况。

        使用 @Insert 注释的 Dao 方法返回:

        1. 如果输入的只有一个数字,则返回一个Long,检查这个Long是否等于一,如果为真则添加成功。

           @Insert
           suspend fun insert( student: Student): Long
          
        2. 如果输入为 varargs 则返回 LongArray,检查 varargs 的大小是否等于 LongArray 大小,如果为 true 则项目添加成功

           @Insert
           suspend fun insert(vararg students: Student): LongArray
          

        【讨论】:

        • insertAll 怎么样?
        • 第二个块插入多个项目,它接受一个可变参数。
        【解决方案7】:

        最简单的方法之一是:

        1. 首先在Android Studio中下载DB Navigator作为插件(更多访问:https://plugins.jetbrains.com/plugin/1800-database-navigator)。

        2. 转到查看>工具窗口>设备文件资源管理器并下载您的数据库实例。

        3. 打开数据库浏览器(从左侧窗格窗口)并浏览您已下载的数据库实例。设置连接,您就可以浏览数据库了。

        4. 有关更多信息,请参阅上面提供的链接。

        【讨论】:

          【解决方案8】:

          我是这样做的(我用协程suspend):

          class SaveVehicle(val repository: RepositoryInterface) {
              suspend fun invoke(vehicleListItem: VehicleListItem): VehicleListItem = 
                  with(vehicleListItem) {
                     also {
                           repository.saveVehicle(vehicleListItem)
                     }
                  }
          }
          

          Kotlin 文档

          inline fun <T> T.also(block: (T) -> Unit): T
          

          以这个值作为参数调用指定的功能块并返回这个值。

          also 适合执行一些将上下文对象作为参数的操作。 also 用于需要引用对象而不是其属性和函数的操作,或者当您不想从外部范围隐藏此引用时。

          您可以查看my example in GitHub:

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2021-07-04
            • 1970-01-01
            • 2018-08-18
            • 1970-01-01
            • 2014-09-24
            相关资源
            最近更新 更多