I have a simple room database with LiveData, i want to get (cartPriceI: Double) values by id to use it within specific methods.
CartItemsDatabase.kt
#Parcelize
#Entity(tableName = "cart_table")
data class CartItemsDatabase(
#PrimaryKey(autoGenerate = true) var cid: Int,
#ColumnInfo(name = "titleD") var cartTitle: String?,
#ColumnInfo(name = "imageD") var cartImage: Bitmap?,
#ColumnInfo(name = "priceLD") var cartPriceL: Double?,
#ColumnInfo(name = "priceID") var cartPriceI: Double?,
#ColumnInfo(name = "itemNumD") var cartNum: Int?,
#ColumnInfo(name = "descriptionD") var cartDes: String?): Parcelable
CartItemsDAO.kt
#Dao
interface CartItemsDAO {
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun addItem(cartItemsDatabase: CartItemsDatabase)
#Update
suspend fun updateCart(cartItemsDatabase: CartItemsDatabase)
#Query("SELECT * FROM cart_table ORDER BY cid ASC")
fun readAllData(): LiveData<List<CartItemsDatabase>>
#Delete
fun delete(cartItems: CartItemsDatabase)
}
CartRepository.kt
class CartRepository(private val cartItemsDAO: CartItemsDAO) {
val readAllData: LiveData<List<CartItemsDatabase>> = cartItemsDAO.readAllData()
suspend fun addItem(cartItemsDatabase: CartItemsDatabase){
cartItemsDAO.addItem(cartItemsDatabase)
}
suspend fun updateCart(cartItemsDatabase: CartItemsDatabase){
cartItemsDAO.updateCart(cartItemsDatabase)
}
}
CartViewModel.kt
class CartViewModel(application: Application): AndroidViewModel(application) {
val readAllData: LiveData<List<CartItemsDatabase>>
private val repository: CartRepository
init {
val cartDao = AppDatabase.getDatabase(application).cartDao()
repository = CartRepository(cartDao)
readAllData = repository.readAllData
}
fun addItem(cartItemsDatabase: CartItemsDatabase){
viewModelScope.launch(Dispatchers.IO){
repository.addItem(cartItemsDatabase)
}
}
fun updateCart(cartItemsDatabase: CartItemsDatabase){
viewModelScope.launch(Dispatchers.IO) {
repository.updateCart(cartItemsDatabase)
}
}
}
AppDatabase.kt
#Database(entities = [CartItemsDatabase::class], version = 1, exportSchema = false)
#TypeConverters(Converters::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun cartDao(): CartItemsDAO
companion object {
#Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
// if the INSTANCE is not null, then return it,
// if it is, then create the database
val tempInstance = INSTANCE
if (tempInstance != null){
return tempInstance
}
synchronized(this){
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"cart_database"
).build()
INSTANCE = instance
return instance
}
}
private fun buildDatabase(context: Context): AppDatabase {
return Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"cartItems_database"
)
.build()
}
}
}
I'm a beginner, i want to know if there is possible way to do that and retrieve specific values from database (ex. cartPriceI in Double) by id!
You can query the database by the given id and return it asynchronously either with a suspend fun or LiveData/Flow
In the CartItemsDAO:
#Query("SELECT cartPriceI FROM cart_table WHERE cid = :id")
suspend fun getPrice(id: Int): Double
#Query("SELECT cartPriceI FROM cart_table WHERE cid = :id")
fun getPrice(id: Int): LiveData<Double>
You can get a specific model by SELECT with WHERE statement
#Query("SELECT * FROM cart_table WHERE cid == : cid")
fun getCartItemsDatabase(cid: String): LiveData<CartItemsDatabase?>
Or you can Return a subset of a table's columns
#Query("SELECT priceID FROM cart_table WHERE cid == : cid")
fun getCartItemPrice(cid: String): LiveData<Double>
Related
java.lang.IllegalArgumentException: A required type converter (class SourceConverter) for ArticlesDao is missing in the database configuration.
I have a crash when compiling (runtime) my application because according to the error displayed, the converter is missing in the configuration of my database. how could I solve this? I need help please.
The source code below:
SourceConverter.kt
#ProvidedTypeConverter
internal class SourceConverter {
#TypeConverter
fun stringToSource(string: String?): SourceEntity = Gson().fromJson(string, SourceEntity::class.java)
#TypeConverter
fun sourceToString(list: SourceEntity?): String = Gson().toJson(list)
}
ArticleEntity.kt
#Entity(tableName = "article")
data class ArticleEntity(
#TypeConverters(SourceConverter::class)
#SerializedName("source")
var source: SourceEntity? = null,
#SerializedName("author")
var author: String? = null,
#SerializedName("title")
var title: String? = null,
#SerializedName("description")
var description: String? = null,
#SerializedName("url")
#NonNull #PrimaryKey var url: String,
#SerializedName("urlToImage")
var urlToImage: String? = null,
#SerializedName("publishedAt")
var publishedAt: String? = null,
#SerializedName("content")
var content: String? = null
)
ArticlesDao.kt
#Dao
interface ArticlesDao {
#Query("select * from article where url = :primaryId")
fun findByPrimaryId(primaryId: String?): ArticleEntity?
#Query("DELETE FROM article WHERE url = :primaryId")
fun deleteByPrimaryId(primaryId: String?): Int
#Query("SELECT * FROM article")
fun getAllArticles(): Flow<List<ArticleEntity>>
#Query("DELETE FROM article")
fun clear()
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(articleEntity: ArticleEntity?): Long
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(vararg articleEntities: ArticleEntity?): LongArray?
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(articleEntityList: List<ArticleEntity?>?): LongArray?
#Update(onConflict = OnConflictStrategy.REPLACE)
fun update(articleEntity: ArticleEntity?): Int
#Update(onConflict = OnConflictStrategy.REPLACE)
fun update(vararg articleEntities: ArticleEntity?): Int
#Update(onConflict = OnConflictStrategy.REPLACE)
fun update(articleEntityList: List<ArticleEntity?>?): Int
#Delete
fun delete(articleEntity: ArticleEntity?): Int
}
AppDatabase.kt
#Database(entities = [ArticleEntity::class, SourceEntity::class], version = 1, exportSchema = false)
#TypeConverters(SourceConverter::class, ArticleConverter::class)
abstract class AppDatabase : RoomDatabase() {
abstract fun getArticlesDao(): ArticlesDao
abstract fun getSourcesDao(): SourcesDao
companion object {
#Synchronized
fun getInstance(context: Context): AppDatabase {
if (sInstance == null) {
sInstance = Room
.databaseBuilder(
context.applicationContext,
AppDatabase::class.java, "infotify.db"
)
.addTypeConverter(SourceConverter::class.java)
.build()
}
return sInstance as AppDatabase
}
}
}
There are three ways to add type converter to room database. But you should make sure you using one method only or it will get error:
add annotation at the type converter class header #ProvidedTypeConverter
Room.databaseBuilder.addTypeConverter(ConverterHelper::class)
add annotation at the RoomDatabase class header #TypeConverters(ConverterHelper::class)
Instead of
Room.databaseBuilder.addTypeConverter(ConverterHelper::class)
Use this:
Room.databaseBuilder.addTypeConverter(ConverterHelper())
If you pass a single id value, then there will be no errors everything works. I pass When the remaining values are wordEn, wordRu, outputs an error:
No value passed for parameter 'wordEn'
No value passed for parameter 'wordRu'
how do I insert a row into a database with columns filled in?
See where <-!!!
#Dao
interface WordDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insert(id: Word, wordEn: Word, wordRu: Word)
}
#Entity(tableName = "word_table")
data class Word (
#PrimaryKey
var id: Int,
var wordEn: String,
var wordRu: List<String>
)
#Database(entities = [Word::class], version = 1, exportSchema = false)
abstract class AppRoomDatabase : RoomDatabase() {
....
....
val instance = Room.databaseBuilder(
context.applicationContext,
AppRoomDatabase::class.java,
"app_room_database"
)
.addCallback(WordDatabaseCallback(scope))
.build()
INSTANCE = instance
instance
}
}
private class WordDatabaseCallback(
private val scope: CoroutineScope
) : RoomDatabase.Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
INSTANCE?.let { database ->
scope.launch(Dispatchers.IO) {
populateDatabase(database.wordDao())
}
}
}
}
suspend fun populateDatabase(wordDao: WordDao) {
//TEST Fill the database with random string
....
....
var randomInt: Int = randomInt()
var randomString: String = randomString()
var list: List<String> = list()
wordDao.insert(Word(randomInt , "$a _$randomString",list)) <- !!!
}
//TEST end
}
The insert statement is not correct
#Dao
interface WordDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertWord(word: Word)
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertWords(words: List<Word>)
#Insert(onConflict = OnConflictStrategy.IGNORE)
suspend fun insertWords1(varargs words: Word)
}
Since Word is an entity
#Entity(tableName = "word_table")
data class Word (
#PrimaryKey
var id: Int,
var wordEn: String,
var wordRu: List<String>
)
Room 🔗 Coroutines
After inserting data into RoomDB when I fetch it using mindValleyDao.getCategories().value It returns null
DatabaseClass
#Database(entities = arrayOf(CategoryBO::class), version = 1, exportSchema = false)
abstract class MindValleyDatabase : RoomDatabase(){
abstract fun mindValleyDao(): MindValleyDao
companion object {
// Singleton prevents multiple instances of database opening at the
// same time.
#Volatile
private var INSTANCE: MindValleyDatabase? = null
fun getDatabase(context: Context): MindValleyDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
MindValleyDatabase::class.java,
"mindvalley_database"
).allowMainThreadQueries()
.fallbackToDestructiveMigration().build()
INSTANCE = instance
return instance
}
}
}
}
CategoryBO.kt
#Entity(tableName = "CategoryEntity")
data class CategoryBO( #PrimaryKey(autoGenerate = true) val id:Int, val name:String)
Doa
#Dao
interface MindValleyDao {
#Query("SELECT * from CategoryEntity ORDER BY id ASC")
fun getCategories(): LiveData<List<CategoryBO>>
#Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(categoryBO: CategoryBO)
//suspend fun insert(categoryBO: CategoryBO)
#Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(categoryBOList: List<CategoryBO>)
}
I am testing it by inserting Category and fetching list of categories like
class MindValleyViewModelNew #Inject constructor() : BaseViewModel() {
var categoryList: MutableLiveData<List<CategoryBO>> = MutableLiveData()
private lateinit var mindValleyDao:MindValleyDao
fun loadDatabase(mContext:Context){
mindValleyDao = MindValleyDatabase.getDatabase(mContext).mindValleyDao()
GlobalScope.launch(Dispatchers.IO) {
mindValleyDao.insert(CategoryBO(0,"first item"))
val cats = mindValleyDao.getCategories().value
categoryList.postValue(cats)
}
}
}
mindValleyDao.getCategories() has return type is LiveData, that's why it query value async, you shouldn't call .value
LiveData type in Room should only use for observe,
If you want to get value, modify your code to fun getCategories(): List<CategoryBO> instead
i am implementing Room with a vIewModel, my structure is the following
#DAO,#Entity,#Database,#Repository
#Entity(tableName="dx_table")
class dx_table(
#ColumnInfo(name = "name")
val naxme: String,
#PrimaryKey
#ColumnInfo(name = "phone")
val phone: String,
#ColumnInfo(name = "passx")
val passx: String,
#ColumnInfo(name = "login_fx")
val login_fx: String
)
#Dao
interface dx_dao{
#Query("SELECT * FROM dx_table")
fun get_all():LiveData<List<dx_table>>
#Insert
suspend fun insertTrx(dx_table:dx_table)
#Query("UPDATE dx_table SET login_fx =:login_fx where phone=:phonex")
suspend fun insertFx(login_fx: String,phonex: String)
#Query("SELECT * from dx_table where phone=:phonex")
suspend fun get_name_px(phonex: String):List<dx_table>
#Query("Delete from dx_table")
suspend fun deleteAll()
#Query("Select * from dx_table where login_fx=1")
suspend fun selectFx():List<dx_table>
}
#Database(entities = arrayOf(dx_table::class), version = 1, exportSchema = false)
public abstract class DxDatabase : RoomDatabase() {
abstract fun dxDao(): dx_dao
companion object {
// Singleton prevents multiple instances of database opening at the
// same time.
#Volatile
private var INSTANCE: DxDatabase? = null
fun getDatabase(context: Context): DxDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
DxDatabase::class.java,
"dx_database"
).build()
INSTANCE = instance
return instance
}
}
}
}
class dxRepository(private val dxDao: dx_dao ){
val k_d:LiveData<List<dx_table>> = dxDao.get_all()
suspend fun insert_trx(dx_table: dx_table){
dxDao.insertTrx(dx_table)
}
suspend fun insert_fx(login_fx: String,phonex: String) {
dxDao.insertFx(login_fx,phonex)
}
suspend fun select_fx() {
dxDao.selectFx()
}
suspend fun get_name_px(phonex: String) :List<dx_table> {
return dxDao.get_name_px(phonex) as List<dx_table>
}
}
The viewmodel is
class DxViewModel (application: Application) : AndroidViewModel(application) {
var repository: dxRepository
var k_d: LiveData<List<dx_table>>
init {
// Gets reference to WordDao from WordRoomDatabase to construct
// the correct WordRepository.
val dxDao = DxDatabase.getDatabase(application).dxDao()
repository = dxRepository(dxDao)
k_d = repository.k_d
}
fun insert_trx(dxTable: dx_table) = viewModelScope.launch {
repository.insert_trx(dxTable)
}
fun insert_fx(login_fx: String, phonex: String) = viewModelScope.launch {
repository.insert_fx(login_fx, phonex)
}
fun select_fx() = viewModelScope.launch {
repository.select_fx()
}
fun get_name_px(phonex: String) = viewModelScope.launch {
repository.get_name_px(phonex)
}
}
I can track the live data using observe,its not an issue, the problem i am facing is with the get_name_px(phone)
var mView = ViewModelProviders.of(this).get(DxViewModel::class.java)
var lm = mView.get_name_px(phone)
here lm seems to be job type , i need the return List , how do i get it .
In your viewModel function select_fx() return a job, because launch does not return result, so you have to either:
1) Use async and await
fun get_name_px(phonex: String) = viewModelScope.async {
repository.get_name_px(phonex)
}.await()
2) Not use launch viewModel, use it in Activity/Fragment
suspend fun get_name_px(phonex: String) = repository.get_name_px(phonex)
class CardFragment : Fragment() {
fun get() {
// launch in Dispatchers.Main
lifecycleScope.launch {
var lm = mView.get_name_px(phone)
}
// launch in background thread
lifecycleScope.launch(Dispatchers.Default) {
var lm = mView.get_name_px(phone)
}
}
}
I'm working with Room persistance databases in android but i get this error
error: Type of the parameter must be a class annotated with #Entity or a collection/array of it.
test.android.orca.com.ws2db.Models.User... user);
Please help me
This is my DAO :
#Dao
abstract interface UserDao
{
#get:Query("SELECT * FROM user")
val getall: List<User>
#Query("SELECT * FROM user where name LIKE :name AND login LIKE :login")
fun findByName(name: String, login: String): User
#Query("SELECT COUNT(*) from user")
fun countUsers(): Int
#Insert
fun insertAll(users: List<User>)
#Delete
fun delete(vararg user: User)
}
This is my Entity
#Entity(tableName = "user")
class UserTable {
#PrimaryKey(autoGenerate = true)
var uid: Int = 0
#ColumnInfo(name = "name")
var name: String? = null
#ColumnInfo(name = "login")
var login: String? = null
#ColumnInfo(name = "id")
var id: Int = 0
#ColumnInfo(name="url")
var url: String? = null
#ColumnInfo(name="company")
var company:String?=null
}
Database
#Database(entities = [UserTable::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun userDao(): UserDao
companion object {
private var INSTANCE: AppDatabase? = null
fun getAppDatabase(context: Context): AppDatabase? {
if (INSTANCE == null) {
INSTANCE = Room.databaseBuilder(context.applicationContext,
AppDatabase::class.java, "user-database")
.allowMainThreadQueries()
.build()
}
return INSTANCE
}
fun destroyInstance() {
INSTANCE = null
}
}}
This is the error : https://i.stack.imgur.com/FnECR.jpg
You are mixing user and UserTable. User is valid for referencing your table, but your entity is UserTable
#Dao
abstract interface UserDao
{
#get:Query("SELECT * FROM user")
val getall: List<UserTable>
#Query("SELECT * FROM user where name LIKE :name AND login LIKE :login")
fun findByName(name: String, login: String): UserTable
#Query("SELECT COUNT(*) from user")
fun countUsers(): Int
#Insert
fun insertAll(users: List<UserTable>)
#Delete
fun delete(vararg user: UserTable)
}