How to time stamp Room database with Long - android

I'm currently adding date/time columns to my current table and want to timestamp when creating an item and add another column of when an item is edited. I'd like to know of when exactly I should timestamp the item and how. I'm seeing an option with System.currentTimeMillis(), but want to make sure it's best practice.
In my prior table I don't have date/time so need to add default values for them as well.
I currently have my Item class as below:
#Entity
class Item
(#field:ColumnInfo(name = "item_name") #get:Bindable var itemName: String) :
BaseObservable() {
#PrimaryKey(autoGenerate = true)
var uid = 0
#ColumnInfo(name = "is_checked")
var isChecked = false
#ColumnInfo(name = "is_listed")
var isListed = false
#ColumnInfo(name = "listed_at")
var listedAt: Long? = System.currentTimeMillis()
#ColumnInfo(name = "created_at")
var createdAt: Long? = System.currentTimeMillis()
}

Related

Add custom but specifc layout itemdecoration between recyclerview items

I have a list of message objects that are being displayed in a recycler view as normal
#Entity(tableName = "messages")
data class Message(
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "message_id")
var messageId: String,
#ColumnInfo(name = "body", defaultValue = "")
var body: String,
#ColumnInfo(name = "msg_type")
var msgType: Int = 0,
#ColumnInfo(name = "message_date", defaultValue = "")
var messageDate: String
)
How ever i want to implement a feature like whatsapp, that by scrolling between messages you can see a message date view like "02 May" that appears only if two messages have messageDate a different day. Should i use a customItemDecoration? But again i can't
How can i implement that?

Room update query

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).

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.

How to make PrimaryKey to generate ids for multiple tables in one order

I have 3 entities(Dishes, Places, Artifacts) which inherit from one abstract class called Memory. Every Memory can store up to 3 photos(string paths) so I set one to many relation Memory-Photo. Photo row contains memory Id as a foreign key so they can be linked together.
The problem is that Android Room creates separate tables for every type of memory so the #AutoGenerate = true annotation generates ids in 3 separate orders for every type of memory.
It causes conflicts because in database there might be 3 memories of different types with the same id so new set of photos would be linked to more than one memory.
I came up with an idea to make primary key out of creation timestamp but it is not the best idea. Maybe there is some way to synchronise key generation mechanism or change the plan of my database.
abstract class Memory(#ColumnInfo(name = "favorite") var favorite: Boolean,
#ColumnInfo(name = "title") var title: String,
#ColumnInfo(name = "date") var date: Date,
#ColumnInfo(name = "description") var description: String,
#Embedded var mapMarker: MapMarker) : Serializable {
#ColumnInfo(name="id")
#PrimaryKey(autoGenerate = true)
var id: Long = 0 }
#Entity(tableName = "artifact_memories")
class ArtifactMemory(favorite: Boolean,
title: String,
date: Date,
description: String,
mapMarker: MapMarker) : Memory(favorite, title,
date, description, mapMarker){}
#Entity(tableName = "dish_memories")
class DishMemory(#ColumnInfo(name = "country_of_origin") var originCountry: String,
#ColumnInfo(name = "type") var dishType: String,
favorite: Boolean,
title: String,
date: Date,
description: String,
mapMarker: MapMarker) : Memory(favorite, title,
date, description, mapMarker) {}
#Entity(tableName = "photos")
data class Photo(#ColumnInfo(name="photo_path") var photoPath: String,
#ColumnInfo(name="memory_id") var memoryId: Long = 0,
#ColumnInfo(name="is_main") var main: Boolean = false) : Serializable {
#PrimaryKey(autoGenerate = true) var id: Long = 0 }
How to deal with such relationships? The goal is to make photos be saved within only one memory and/or remove conflicts with id duplicates.
you can use inheritSuperIndices property to make sure that every child class inherits super class's primary key
#Entity(tableName = "artifact_memories",inheritSuperIndices = true)
class ArtifactMemory(favorite: Boolean,
title: String,
date: Date,
description: String,
mapMarker: MapMarker) : Memory(favorite, title,
date, description, mapMarker){}
#Entity(tableName = "dish_memories",inheritSuperIndices = true)
class DishMemory(#ColumnInfo(name = "country_of_origin") var originCountry:
String,
#ColumnInfo(name = "type") var dishType: String,
favorite: Boolean,
title: String,
date: Date,
description: String,
mapMarker: MapMarker) : Memory(favorite, title,
date, description, mapMarker) {}
#Entity(tableName = "photos",inheritSuperIndices = true)
data class Photo(#ColumnInfo(name="photo_path") var photoPath: String,
#ColumnInfo(name="memory_id") var memoryId: Long = 0,
#ColumnInfo(name="is_main") var main: Boolean = false) : Serializable {
#PrimaryKey(autoGenerate = true) var id: Long = 0 }

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