I want to know that how can i sum value in the room database .
Let say i have insert this value (10,000) in the room database and i want to insert new value to database (20,000) and i want the new value to be sum with old value not replace it .
how can i do that .?
example of code :
Database Table :
#entity
class sum (
id : int ,
value : Long )
Dao :
#insert (onConflict = OnConflictStrategy.REPLACE)
suspend fun insert (model :sum)
what shoud i use instead of above insert .
#Query("SELECT * FROM sum")
fun getall () : LiveData<sum>
and in activity :
late init var : viewmodel : Viewmodeldatabase
val textvalue : TextView
viewmodel = Viewmodelprovider(this).get(Viewmodeldatabase::class.java)
textvalue = findvidwbyid(R.id.text)
viewmodel.insert(sum(1 , 10000)
// when the above value insert , if there is an old value sum with it and not replace it or remove it
viewmodel.getall.observe(this , Observer {
textvalue.text = it.value
)}
thank's guys for watch my code and help me .
Try to add next method in your dao:
#Query("UPDATE sum SET value = value + :addValue WHERE id =:id")
suspend fun updateSum(id: Int, addValue: Long)
Then you can call it from your ViewModel/Activity
UPDATE
For single method for update/insert put these methods in dao:
#Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun insertSum(model: Sum)
#Query("UPDATE sum SET value = value + :value WHERE id = :id")
suspend fun updateSum(id: Int, value: Long)
#Query("SELECT * FROM sum WHERE id = :id")
suspend fun getSumById(id: Int): Sum?
#Transaction
suspend fun updateOrInsertSum(sum: Sum) { // <-- this method updates value or insert new item, if id is not found
getSumById(sum.id)?.let { updateSum(sum.id, sum.value) } ?: insertSum(sum)
}
Of course you should add method updateOrInsertSum to your repository and viewmodel as well
Then if you call for id = '1' for the first time value will be inserted:
viewmodel.updateOrInsertSum(Sum(1 ,10000)) // <-- id = 1, value = 10000
On the next call item will be updated with the same method:
viewmodel.updateOrInsertSum(Sum(1 ,20000)) // <-- id = 1, value = 10000+2000
In your Dao, I see that you use the function getAll(),
lets say that you save them into a list of integers
val list: List<Int>//list holding all of you data returned in the onChanged method of the observer callback(or the lambda callback in case of Kotlin)
lets say that you want to update the value at position 1:
#Update
public void update(newVal: Int);
and when calling the update function pass to it the summation of the old value coming from the "list" I mentioned earlier and the newValue
database.dao.update(list[1] + newValue)
Related
Quiz app, categories have questions and questions have answers.
I have two queries in the DAO.
In the first one, I get all the categories from the data:
#Query("SELECT * from category_table ORDER BY category_id")
fun getAllCategories(): LiveData<List<Category>>
In the second one, I get a list of questions and answers by category id:
#Query("SELECT * FROM question_table WHERE parent_category_id = :categoryId ")
fun getQuestionsWithAnswersByCategoryId(categoryId: Long): LiveData<List<QuestionWithAnswers>>
Repository:
val getAllCategories: LiveData<List<Category>> = quizDao.getAllCategories()
fun getQuestionsWithAnswersByCategoryId(id: Long): LiveData<List<QuestionWithAnswers>> {
return quizDao.getQuestionWithAnswers(id)
}
This is my viewmodel:
val getAllCategories: LiveData<List<Category>>
var questionById: LiveData<List<QuestionWithAnswers>>
init {
getAllCategories = repository.getAllCategories
questionByCategoryId = repository.getQuestionWithAnswersByCategoryId(???????)
}
The problem is that I don't know the categories' id beforehand and need to obtain them from the database.
when I try to obtain a category id in the viewmodel like this:
var categoryId = getAllCategories.value[0].categoryId
it returns null.
Is there any way to obtain categories id which wrapped in livedata inside a viewmodel?
I have simple data object that I want to insert into room database but as I am using auto increment on my primary key I am doing it as below
#Dao
interface T1Dao {
#Query("INSERT INTO tbl_t1(data1, data2) VALUES ( :T1.data1, :T1.data2) ")
fun insert(note: T1): Long
}
I have many properties in T1 so I don't want pass them separately if possible.
In above example I am just showing two properties.
But you can just use #Insert and not to set your primary key field, can't you?
#Insert
fun insert(note: T1): Long
Let's say you have T1 class:
#Entity
data class T1(
#PrimaryKey(autoGenerate = true)
val id: Int = 0, // This lets you not to set id before inserting
val data1: String,
val data2: String
)
Then you can insert:
dao.insert(T1(data1 = "data1", data2 = "data2")) // just don't set id
I am practicing my android skills (beginner) by coding a grocery list app. I have two tables in my db, a shopping_item table (The items I want to buy) and a reference_item table (The items I know the category and the unit price). Each time I add a shopping item, there is an refId field referencing to the reference item id corresponding. It is a default value to a default reference item if the shopping item is not referenced yet.
I use a MVVM model. I then have a DAO, a repository, a viewModel and my fragments that display data.
When I add a new shopping item, I want to know if there is a corresponding reference item. I want to do the following Query:
#Query(value = "SELECT refId FROM reference_items WHERE reference_item_name = :refName")
suspend fun getRefItem(refName : String) : Int
It returns the id of the reference item corresponding as an Int or is null if it is not referenced yet. In my repository, I have a function like that:
suspend fun getRefItem(refName : String) = db.getShoppingDao().getRefItem(refName)
For now, I think I am doing alright. No mistake in sight I guess.
The problem begin when I try to implement my viewModel. What should I do? What about my fragment?
I have a addNewItem(name: String, amount: Int) function in my fragment to add the new item. I can find the reference item corresponding with the name provided.
I tried multiple things, using LiveData, suspend functions, mutableLiveData/LiveData, but I am getting lost right now. Every tutorials or examples use LiveData or Query all data from the db. I just want one Integer, one Time, no need of LiveData I think.
here is the complete solution. Hope this is useful for you.
DAO
#Query(value = "SELECT refId FROM reference_items WHERE reference_item_name = :refName")
suspend fun getRefItem(refName : String) : Int
Repository
// Specify return datatype as Int
suspend fun getRefItem(refName : String): Int = db.getShoppingDao().getRefItem(refName)
ViewModel
fun getRefItem(name: String): LiveData<Int> {
val result : MutableLiveData<Int>() <-- setup livedata to return as value
viewModelScope.lanuch {
result.postValue(repository.getRefItem(name))
}
return result <-- return livedata
}
Fragment
fun addNewItem(name: String, amount: Int) {
// setup viewModel observer
viewModel.getRefItem(name).observer { viewLifecycleOwner, { value ->
// GET YOUR INT VALUE HERE
Log.i("VALUE", value)
}
}
}
I am using Room Database to make a database to store information in a table. I want to access one entry from the table and delete the same entry without the need to call two functions.
#Query("SELECT * FROM history_packet_table ORDER BY timestamp ASC LIMIT 1")
fun get(): HistoryPacket?
#Query("DELETE FROM history_packet_table ORDER BY timestamp ASC LIMIT 1")
fun delete()
I want these two operations to happen only by calling get. Is there a way?
I believe that you can add the following to the Dao :-
#Transaction
fun getAndDelete() {
get()
delete()
}
Obviously you can call the function what you wish. However, the get seems to be useless as it is.
So you may want something like :-
#Query("SELECT * FROM history_packet_table WHERE timestamp = (SELECT min(timestamp) FROM history_packet_table)")
fun get() :HistoryPacketTable
#Query("DELETE FROM history_packet_table WHERE timestamp = (SELECT min(timestamp) FROM history_packet_table)")
fun delete() :Int
#Transaction
fun getAndDelete() :HistoryPacketTable {
// Anything inside this method runs in a single transaction.
var rv: HistoryPacketTable = get()
val rowsDeleted: Int = delete()
if (rowsDeleted < 1) {
rv = HistoryPacketTable();
//....... set values of rv to indicate not deleted if needed
}
return rv
}
Note as LIMIT on delete is turned off by default, the queries can be as above, this assumes that timestamp is unique otherwise multiple rows may be deleted, in which case the Dao could be something like
:-
#Delete
fun delete(historyPacketTable: HistoryPacketTable) :Int
#Transaction
fun getAndDelete() :HistoryPacketTable {
// Anything inside this method runs in a single transaction.
var rv: HistoryPacketTable = get()
val rowsDeleted: Int = delete(rv)
if (rowsDeleted < 1) {
rv = HistoryPacketTable();
//....... set values to indicate not deleted
}
return rv
}
I try yo use Room with Kotlin and RxJava 2.
I have an entity with a string primary key and I would like to be notified when values are updated but I receive new value from flowable even if the value isn't updated when I had whatever value.
Entity :
#Entity
class MarketSummaryModel(#PrimaryKey var marketName: String)...
Dao :
#Dao
interface MarketSummaryDao {
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insert(marketSummaryModel: MarketSummaryModel)
#Query("select * from MarketSummaryModel where marketName = :marketName LIMIT 1")
fun getByName(marketName: String): Flowable<MarketSummaryModel>
}