База данных журналов DAO для Android
С учетом базы данных DAO, как это:
import android.arch.persistence.room.Dao;
import android.arch.persistence.room.Query;
import java.util.Date;
import java.util.List;
@Dao
public interface MyDao {
@Query("SELECT * FROM MyTable")
List<MyItem> all();
@Query("SELECT * FROM MyTable WHERE date = :date AND language = :language")
MyItem byDate(Date date, String language);
}
Есть ли способ иметь Logger или что-то подобное, добавленное в MyDao
, чтобы я мог видеть, какие операторы выполняются. Это было бы очень полезно во время разработки, потому что я мог сразу проверить правильность преобразования функций в ожидаемый оператор SQL или нет.
Ответы
Ответ 1
На уровне DAO, похоже, нет никаких зацепок для этого. Есть обратные вызовы, связанные с открытием и обновлением базы данных, но не произвольные вещи.
Вы можете подать запрос на функцию, хотя. Я согласен, что это может быть полезно. Еще лучше будет универсальная структура перехватчика в стиле OkHttp.
Ответ 2
Согласно документу Room, он выполняет проверку времени компиляции, поэтому, если ваш SQL-оператор недопустим, сама компиляция не удалась, и в журнале отображается правильное сообщение об ошибке.
Также сгенерированный код является отлаживаемым по умолчанию и может быть найден по указанному ниже пути.
сборка> созданная> исходная> apt> ваш пакет> yourDao_Impl.java
Этот класс содержит реализацию вашего DAO, вы можете отлаживать этот класс по мере отладки других классов в вашем проекте. :-)
Пример:
![enter image description here]()
Ответ 3
Когда у меня есть некоторая неизвестная ошибка при вставке или обновлении строки в комнате db Android не обнаруживает ошибок в консоли отладки. Одна вещь, которую я нашел, как проверить, что происходит во время отладки:
try { someSource.update(someRow) } catch (e: Throwable) { println(e.message) }
Выход:
Ошибка UNIQUE: quiz.theme(код 2067)
Ответ 4
Я смог добиться этого с помощью хака для запросов Select. Это не будет работать для операций вставки/обновления/удаления :)
Создайте отдельный класс RoomLoggingHelper
следующим образом
import android.annotation.SuppressLint
import androidx.room.RoomSQLiteQuery
private const val NULL = 1
private const val LONG = 2
private const val DOUBLE = 3
private const val STRING = 4
private const val BLOB = 5
private const val NULL_QUERY = "NULL"
const val ROOM_LOGGING_TAG = "roomQueryLog"
object RoomLoggingHelper {
@SuppressLint("RestrictedApi")
fun getStringSql(query: RoomSQLiteQuery): String {
val argList = arrayListOf<String>()
val bindingTypes = query.getBindingTypes()
var i = 0
while (i < bindingTypes.size) {
val bindingType = bindingTypes[i]
when (bindingType) {
NULL -> argList.add(NULL_QUERY)
LONG -> argList.add(query.getLongBindings()[i].toString())
DOUBLE -> argList.add(query.getDoubleBindings()[i].toString())
STRING -> argList.add(query.getStringBindings()[i].toString())
}
i++
}
return String.format(query.sql.replace("?", "%s"), *argList.toArray())
}
fun getStringSql(query: String?, args: Array<out Any>?): String? {
return if (query != null && args != null) {
String.format(query.replace("?", "%s"), *args)
} else
""
}
}
private fun RoomSQLiteQuery.getBindingTypes(): IntArray {
return javaClass.getDeclaredField("mBindingTypes").let { field ->
field.isAccessible = true
[email protected] field.get(this) as IntArray
}
}
private fun RoomSQLiteQuery.getLongBindings(): LongArray {
return javaClass.getDeclaredField("mLongBindings").let { field ->
field.isAccessible = true
[email protected] field.get(this) as LongArray
}
}
private fun RoomSQLiteQuery.getStringBindings(): Array<String> {
return javaClass.getDeclaredField("mStringBindings").let { field ->
field.isAccessible = true
[email protected] field.get(this) as Array<String>
}
}
private fun RoomSQLiteQuery.getDoubleBindings(): DoubleArray {
return javaClass.getDeclaredField("mDoubleBindings").let { field ->
field.isAccessible = true
[email protected] field.get(this) as DoubleArray
}
}
private fun RoomSQLiteQuery.getIntBindings(): IntArray {
return javaClass.getDeclaredField("mBindingTypes").let { field ->
field.isAccessible = true
[email protected] field.get(this) as IntArray
}
}
Или вы можете скачать этот файл здесь
Добавьте этот файл в ваш проект и вызовите его из класса Room Database следующим образом: переопределите оба метода query
следующим образом
override fun query(query: SupportSQLiteQuery?): Cursor {
//This will give you the SQL String
val queryString = RoomLoggingHelper.getStringSql(query as RoomSQLiteQuery)
//You can log it in a way you like, I am using Timber
Timber.d("$ROOM_LOGGING_TAG $queryString")
return super.query(query)
}
override fun query(query: String?, args: Array<out Any>?): Cursor {
//This will give you the SQL String
val queryString = RoomLoggingHelper.getStringSql(query, args)
//You can log it in a way you like, I am using Timber
Timber.d("$ROOM_LOGGING_TAG $queryString")
return super.query(query, args)
}
Отказ от ответственности:
- Я использую Reflection для получения строкового SQL, следовательно, используйте это ТОЛЬКО в режиме отладки
- Это написано на скорую руку и может содержать ошибки, было бы целесообразно сохранить его в блоке
try-catch
- Кроме того, я проверил его на строковые аргументы, должен работать долго и дважды, не будет работать для
Blobs