Room update query - android

I'm using Room persistence library for Android and trying to make 'update' query for the boolean field.
#Update
suspend fun updateProduct(product: Product)
Product entity:
#Entity(tableName = "products")
data class Product(
#ColumnInfo(name = "name") val name: String = "",
#ColumnInfo(name = "price") val price: Int = 0,
#ColumnInfo(name = "count") val count: Int = 0,
#ColumnInfo(name = "description") val description: String = "",
#ColumnInfo(name = "isPurchased") val isPurchased : Boolean = false
) {
#PrimaryKey var id: String = UUID.randomUUID().toString()
#ColumnInfo(name = "date") var date: Long = Date().time
}
Similar queries as delete, insert work fine. The underhood query should find the id of product and update all fields but it doesn't work. Please don't write about insert query instead update, it's a dirty trick.
Update: update method returns 0 and it means it doesn't work, according to docs it should return num of updated record:
Although usually not necessary, you can have this method return an int
value instead, indicating the number of rows updated in the database.

you can try this
#Query("UPDATE products SET price=:price WHERE id = :id")
void update(Float price, int id);

Regarding the docs it says you have to do something like this:
#Update
fun updateProduct(product: Product) // no need of suspend
also you can control what happen onConflict. Note that if you don't specify by default it is OnConflictStrategy.ABORT which roll back the transaction and does nothing. So you might wanna add something like #Update(onConflict = OnConflictStrategy.REPLACE).

Related

Android - Room query always returns row's id=0?

I have a query like this in my room Dao
#Query("SELECT * FROM my_data ORDER BY id ASC LIMIT 1")
suspend fun getFirstItem(): MyEntity?
and MyEntity is just a data class with an auto generated id.
#Entity(tableName = "my_data")
data class MyEntity(
#PrimaryKey(autoGenerate = true)
val id: Int = 0,
#ColumnInfo(name = "date_created")
var dateCreated: String? = null,
#ColumnInfo(name = "description")
var description: String? = null
)
When I run the query the entity object that is returned has always id=0.
How can I get the actual id of the row using a query in room?
EDIT: This is the function I'm calling the query
suspend fun getFirstItem(context: Context): MyEntity? {
val db = MyDatabase.getDb(context)
return db.MyDao().getFirstItem()
}
The returned MyEntity object is something like this.
MyEntity(id=0, dateCreated="2022-12-07 09:38:37", description="some description")
Where the id is always returned as 0, although it isn't actually 0
In My System, Your Query works Properly.
All Available Entries
Query Result
Do invalid catch/Restart and Try again

How can I query a record of part fields using Room in Android Studio with Kotlin?

It works well to query record MVoice using fun listVoice():LiveData<List<MVoice>> with Room framework in Android Studio with Kotlin.
Now I hope to query record of part fields (Such as ID and name) of MVoice, how can I do?
interface DBVoiceDao{
#Query("SELECT * FROM voice_table ORDER BY createdDate desc")
fun listVoice():LiveData<List<MVoice>>
/* How can I do this?
#Query("SELECT id, name FROM voice_table ORDER BY createdDate desc")
fun listVoiceOfPartField():LiveData< ??? >
*/
}
#Entity(tableName = "voice_table", indices = [Index("createdDate")])
data class MVoice(
#PrimaryKey (autoGenerate = true) #ColumnInfo(name = "id") var id: Int = 0,
var name: String = "Untitled",
var path: String = "My path",
var createdDate: Calendar = Calendar.getInstance(),
var isStar: Boolean = false,
var description: String="My description"
)
As "Florina Muntenescu" suggested that Read only what you need in this article 7 Pro-tips for Room
You can achieve it by making a new Model Class:
data class VoiceMinimal(#ColumnInfo(name = "id") val id: Int,
#ColumnInfo(name = "name") val name: String)
In the DAO class, we define the query and select the right columns from the voice table.
#Dao
interface DBVoiceDao {
#Query(“SELECT id, name FROM voice_table ORDER BY createdDate dESC)
fun getVoiceMinimal(): List<VoiceMinimal>
}

simple Room query in Android app doesn't work

I'm following an Android development tutorial that uses Room to store data and retrieve it.
I have the following entity:
#Entity
data class DogBreed(
#ColumnInfo(name = "breed_id")
val breedId: String?,
#ColumnInfo(name = "dog_name")
val dogBreed: String?,
#ColumnInfo(name = "life_span")
val lifeSpan: String?,
#ColumnInfo(name = "breed_group")
val breedGroup: String?,
#ColumnInfo(name = "bred_for")
val bredFor: String?,
val temperament: String?,
#ColumnInfo(name = "dog_url")
val imageUrl: String?
) {
#PrimaryKey(autoGenerate = true)
var uuid: Int = 0
}
and the following Room DAO:
#Dao
interface DogDao {
#Insert
suspend fun insertAll(vararg dogs: DogBreed): List<Long>
#Query("SELECT * FROM dogbreed")
suspend fun getAllDogs(): List<DogBreed>
#Query("SELECT * FROM dogbreed WHERE uuid = :dogId")
suspend fun getDog(dogId: Int): DogBreed?
#Query("DELETE FROM dogbreed")
suspend fun deleteAllDogs()
}
The insertAll method works fine. I can retrieve all data using getAllDogs() and the uuid is auto-generated as intended. However, the getDog(dogId) method does not work. It always returns null.
It's a simple query and I don't see anything wrong with it. What could be the issue?
The query is used in the following code:
val dao = DogDatabase(getApplication()).dogDao()
val dog = dao.getDog(uuid)
Toast.makeText(getApplication(), "Dog from DB ${uuid} / $dog", Toast.LENGTH_SHORT).show()
The toast shows something like "Dog from DB 12 / null".
It turned out that the uuid, which was supplied as an action parameter when navigating from a different fragment, was not the correct value. It was the breedId instead of the uuid property.
I used Room a couple of time but it seems your uuId is an Int type and you are using a String type in your query. As far as I remember you have to use like for sql queries.
My guess is that you have to use both Int values or String values but not a mixed of it. And if you are using String type use Like instead of equal.
"SELECT * FROM dogbreed WHERE uuid like :dogId"

How to autogenerate a Room database id without providing an id

I am trying to create a room database and I want each item inserted into it to have its own unique id without me having to provide it, The problem is when I try to insert new items into the database I get an error asking me to provide an id.
Here is my entity:
#Entity(tableName = "notes_table")
data class Note(
#PrimaryKey(autoGenerate = true)
val id: Int = 0,
#ColumnInfo(name = "description")
val description: String,
#ColumnInfo(name = "priority")
var priority: Int)
Is there a way to have the database create its own auto-generated auto-increasing id column without having me having to add it like this:
val item = Note(id, item, priority)
insert(item)
And instead do this:
val item = Note(item, priority)
insert(item)
Create a constructor that takes item and priority as arguments
#Entity(tableName = "notes_table")
data class Note (var item: String,
#ColumnInfo(name = "priority")
var priority: String) {
#PrimaryKey(autoGenerate = true)
var id: Long = 0,
//.....
}
You can just simply give the id a default value and put that at the end:
#Entity(tableName = "notes_table")
data class Note(
#ColumnInfo(name = "description")
val description: String,
#ColumnInfo(name = "priority")
var priority: Int)
#PrimaryKey(autoGenerate = true) //must be at the end
val id: Int = 0 //Long type recommend
)
Then you can:
val item = Note(item, priority)
insert(item)
Because your data class Note has three parameter.
So you you have to create Note by passing three parameter.
It is nothing to do with autogenerate or room.

Check if an entry is already in a livedata list wihout looping through the list

I am trying to build an app to help me track some of the tasks we have to do in the game.
I have a Firebase Firestore database that store all the tasks and I download at the application launch the data and add only the one I don't have.
Here is my entry model:
#Entity(tableName = "entry_table")
data class Entry(
#PrimaryKey(autoGenerate = true) var uid: Long?,
#ColumnInfo(name = "title") val title: String,
#ColumnInfo(name = "description") val description: String,
#ColumnInfo(name = "target") val target: Int = 0,
#ColumnInfo(name = "position") val position: Int = 0,
#ColumnInfo(name = "starred") val starred: Boolean = false
) {
constructor(): this(null, "", "", 0, 0, starred = false)
}
Since I download the document from the firestore database I cannot set an ID before inserting the entries in my SQLite database.
This means that I cannot use the "contains" method on my livedata list (since the entries I recieve has a "null" id and the one from the database has an id). I need to loop though all the data, here is the code:
#WorkerThread
suspend fun insertEntry(entry: Entry) {
for (doc in entriesList.value!!){
if (doc.description == entry.description && doc.title == entry.title) {
Log.d("MAIN_AC", "Entry already saved $entry")
return
}
}
entryDAO.insertEntry(entry)
}
My code works but I am not satisfied with it, is there a better way to make this happen? I was hoping that the contains method could ignore some arguments (in my case the autogenerated ID)
One way you can go about, assuming you are using Room, it is to annotate your insert function (in the relevant DAO) with OnConflictStrategy.IGNORE.
e.g.
#Dao
interface EntryDao {
#Insert(onConflict = OnConflictStrategy.IGNORE)
fun insert(list: List<Entry>)
// or (if you want the inserted IDs)
// fun insert(list: List<Entry>) : LongArray
}
Be sure to also annotate your entity with the relevant unique index.
e.g.
#Entity(tableName = "entry_table",
indices = [Index(value = ["title", "description"], unique = true)]
)
data class Entry(
#PrimaryKey(autoGenerate = true) var uid: Long,
#ColumnInfo(name = "title") val title: String,
#ColumnInfo(name = "description") val description: String
//...
)
Primary keys should not be null-able, you can .map to Entry wit uid = 0. If you are using the same entity model both locally and remotely that is probably not the best idea.

Categories

Resources