Reputation: 95
I watched the youtube video and implemented database in my project
Database.kt:
@Database(entities = [Result::class], version = DATABASE_VERSION, exportSchema = false)
abstract class ResultDatabase : RoomDatabase() {
abstract fun resultDao(): ResultDao
companion object {
@Volatile
private var INSTANCE: ResultDatabase? = null
fun getDatabase(context: Context): ResultDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
ResultDatabase::class.java,
TABLE_NAME
).build()
INSTANCE = instance
return instance
}
}
}
}
ResultClass.kt:
@Entity(tableName = TABLE_NAME)
data class Result(private val id: Int,
private val cheatingEnabled: Boolean,
private val cheatingSuccessful: Boolean,
private val min: Long,
private val max: Long,
private val result: Long,
private val time: LocalDateTime
)
ResultDao.kt:
@Dao
interface ResultDao {
@Insert(onConflict = OnConflictStrategy.IGNORE)
fun addResult(result: Result)
@Query(value = "SELECT * FROM random_data ORDER BY id ASC")
fun getAllResults(): LiveData<List<Result>>
}
Repo.kt
class ResultsRepository(private val resultDao: ResultDao) {
val resultHistory: LiveData<List<Result>> = resultDao.getAllResults()
fun addResult(result: Result) {
resultDao.addResult(result)
}
}
Function that inserts data to database:
private fun insertDataToDatabase(min: Long,
max: Long,
result: Long,
cheatingEnabled: Boolean,
cheatingSuccessful: Boolean
) {
val time = LocalDateTime.now()
val resultEntity = Result(0, cheatingEnabled, cheatingSuccessful, min, max, result, time)
viewModelScope.launch {
repository.addResult(resultEntity)
}
}
Error:
C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:14: error: Cannot figure out how to save this field into database. You can consider adding a type converter for it.
private final java.time.LocalDateTime time = null;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:8: error: Cannot find getter for field.
private final int id = 0;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:9: error: Cannot find getter for field.
private final boolean cheatingEnabled = false;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:10: error: Cannot find getter for field.
private final boolean cheatingSuccessful = false;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:11: error: Cannot find getter for field.
private final long min = 0L;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:12: error: Cannot find getter for field.
private final long max = 0L;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:13: error: Cannot find getter for field.
private final long result = 0L;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:14: error: Cannot find getter for field.
private final java.time.LocalDateTime time = null;
^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:7: error: An entity must have at least 1 field annotated with @PrimaryKey
public final class Result { ^C:\Users\Maxim\AndroidStudioProjects\AdvancedNumberGenerator\app\build\tmp\kapt3\stubs\debug\com\example\advancednumbergenerator\database\Result.java:14: error: Cannot figure out how to read this field from a cursor. private final java.time.LocalDateTime time = null; ^
How can I fix this error? Can it be connected with using LocalDateTime datatype and Long instead of int? But I don't even start inserting, I get errors while building. I saw similar questions and there people adviced to use json objects, but man from youtube has project without json and withoutany errors.
Upvotes: 1
Views: 369
Reputation: 1007554
Can it be connected with using LocalDateTime datatype and Long instead of int?
Yes.
But I don't even start inserting, I get errors while building
Room uses an annotation processor — that is the kapt
statement you added to your dependencies
. That annotation processor does not know what to do with a LocalDateTime
. And, it cannot work with private
Kotlin properties.
How can I fix this error?
Start by removing the private
keyword from those properties on Result
. That should reduce the errors to 2, both for LocalDateTime
.
Then, you will need to teach Room how to work with LocalDateTime
.
For that, you will need a class with a pair of @TypeConverter
functions that can convert between LocalDateTime
and... something. In this sample, I have type converters between Instant
and Long
:
import androidx.room.TypeConverter
import java.time.Instant
class TypeTransmogrifier {
@TypeConverter
fun fromInstant(date: Instant?): Long? = date?.toEpochMilli()
@TypeConverter
fun toInstant(millisSinceEpoch: Long?): Instant? = millisSinceEpoch?.let {
Instant.ofEpochMilli(it)
}
}
Then, you will need to add a @TypeConverters
annotation (note the trailing s
) to something to register your class with the @TypeConverter
annotations. One simple place to do this is on your @RoomDatabase
class, as I do in this sample:
import android.content.Context
import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverters
private const val DB_NAME = "stuff.db"
@Database(entities = [ToDoEntity::class], version = 1)
@TypeConverters(TypeTransmogrifier::class)
abstract class ToDoDatabase : RoomDatabase() {
abstract fun todoStore(): ToDoEntity.Store
companion object {
fun newInstance(context: Context) =
Room.databaseBuilder(context, ToDoDatabase::class.java, DB_NAME).build()
}
}
Given those two things, in my sample project, any of my entities can use Instant
. You would do the same thing, just for LocalDateTime
(or, perhaps, switch your entities from using LocalDateTime
to using Instant
).
You can read more about this in the documentation.
Upvotes: 1