How to save numbers in room database kotlin - kotlin

I want to create a simple financial report app.
With opening balance, inventory purchase, other expenses, sales and banking all as double numbers I want to use room database, jetpack components

You can't ask this type of questions but look at this sample (simplest way to use roomDB)
First of all you need to define you database class
#Database(entities = [CompaniesModel::class, UserPoint::class], version = 15) //here is the models which will have the structure of your database
abstract class DataBase : RoomDatabase() {
/**
* define companies dao to make some quires
*/
abstract fun homeDao(): HomeDao
abstract fun companiesDao(): CompaniesListDao
companion object {
#Volatile
private var databaseInstance: DataBase? = null
fun getDatabaseInstance(mContext: Context): DataBase =
databaseInstance ?: synchronized(this) {
databaseInstance ?: buildDatabaseInstance(mContext).also {
databaseInstance = it
}
}
private fun buildDatabaseInstance(mContext: Context) =
Room.databaseBuilder(mContext, DataBase::class.java, "crm")
.fallbackToDestructiveMigration()
.allowMainThreadQueries()
.build()
}
}
and the models which contain the structure of your database
#Entity(tableName = "companiesModel")
data class CompaniesModel(
#PrimaryKey
#ColumnInfo(name = "id")
#SerializedName("id")
var id: Int,
#ColumnInfo(name = "name")
#SerializedName("name")
var name: String,
#ColumnInfo(name = "image")
#SerializedName("image")
var image: String
)
and the Dao which have all your queres
#Dao
interface CompaniesListDao {
/**
* this fun to insert data in room db after fetch data from server
*/
#Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertCompanies(contactModel: List<CompaniesModel>)
/**
* this fun to get data from room db to make some caching in app
*/
#Query("SELECT * FROM companiesModel")
fun getCompaniesList(): List<CompaniesModel>
/**
* this fun to clear companies list from room db
*/
#Query("DELETE FROM companiesModel")
fun clearCompaniesList()
#Update
fun update(contactModel: List<CompaniesModel>)
}
to access the data you should call it like this
DataBase.getDatabaseInstance(App.instance).companiesDao().something

Related

How to get two data from Hashmap in room database?

I took the data from a money exchange API and saved it to the room. I want to extract 2 values ​​from the data I saved, for example, the user wants to convert 120 dollars to euros. I will take the conversion rate of the dollar and the conversion rate of the euro from my room database and convert it with a mathematical operation accordingly. However, I did not know how to get these two values ​​from my data that I keep as Hashmap.
I wrote a code like this,
dao
#Dao
interface ExchangeDao {
#Query("SELECT * FROM ExchangeValues WHERE conversion_rates=:currency")
suspend fun getConversionRateByCurrency(currency : String) : Double
}
entity
#Entity(tableName = "ExchangeValues")
data class ExchangeEntity(
#ColumnInfo(name = "base_code") val base_code: String,
#ColumnInfo(name = "conversion_rates") val conversion_rates: HashMap<String,Double>,
#ColumnInfo(name = "result") val result: String,
#PrimaryKey(autoGenerate = true) val uid:Int?=null
)
repositoryImpl
class ExchangeRepositoryImpl #Inject constructor(
private val dao:ExchangeDao,
private val api: ExchangeApi
) : ExchangeRepository{
override suspend fun getConversionRateByCurrency(currency: String): Double {
return dao.getConversionRateByCurrency(currency)
}
}
repository
interface ExchangeRepository {
suspend fun getConversionRateByCurrency(currency : String) : Double
}
use case
class GetConversionRateByCurrencyUseCase #Inject constructor(
private val repository: ExchangeRepository
) {
suspend fun getConversionRateByCurrency(currency:String) : Double {
return repository.getConversionRateByCurrency(currency)
}
}
but it gave an error like this
error: Not sure how to convert a Cursor to this method's return type (java.lang.Double).
public abstract java.lang.Object getConversionRateByCurrency(#org.jetbrains.annotations.NotNull()
error: The columns returned by the query does not have the fields [value] in java.lang.Double even though they are annotated as non-null or primitive. Columns returned by the query: [base_code,conversion_rates,result,uid]
public abstract java.lang.Object getConversionRateByCurrency(#org.jetbrains.annotations.NotNull()

Room query with id doesn't return the right list RxJava MVVM architecture

I have a problem concerning my query returns, I have a student class that contains a string id from another table
data class StudentEntity(
#PrimaryKey
val idStudent: String,
val classId: String,
val name: String,
val notes: Note?,
)
I also created a room database that I'm populating from my api call
#Database(entities = [Student::class, Note::class], version = 14, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun programDAO(): ProgramDAO
companion object{
#Volatile
private var INSTANCE: AppDatabase? = null
fun getInstance(context: Context) : AppDatabase {
synchronized(this) {
var instance = INSTANCE
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext, AppDatabase::class.java, "student-database"
).fallbackToDestructiveMigration().build()
INSTANCE = instance
}
return instance
}
}
}
}
and for that, I have a programDao that helps me to run my queries
#Dao
interface ProgramDAO {
#Transaction
#Query("select * from studentEntity")
fun getStudents(): Single<List<StudentEntity>>
#Transaction
#Query("select * from studentEntity where classId = :classid")
fun getStudentsWithId(classid: String): Single<List<StudentEntity>>
}
In order to execute those queries, I have my Repository:
class ProgramRepository(val api: ApiService, val programDAO: ProgramDAO) {
fun getStudentsFromDbWithId(idClass: String) : Observable<StudentEntity>{
return programDAO.getStudentsWithId(idClass).toObservable()
}
fun getStudentsFromDb() : Observable<StudentEntity>{
return programDAO.getStudents().toObservable()
}
}
The MV allows me to connect the data and the view:
class ProgramListViewModel(private val programRepository: ProgramRepository) {
fun getListFromDBWithId(classID: String): Observable<List<StudentEntity>> {
return programRepository.getStudentsFromDbWithId(deliverySiteId)
}
fun getListFromDB(): Observable<List<StudentEntity>> {
return programRepository.getStudentsFromDb()
}
}
So in order to use the data and get the adapter and the KPIs on my fragment, I don't receive the right list from the database, I did log the results to see what I get, to start, I do log the whole list without id, and I have the list, but when I use an ID like:
subscribe(programListViewModel.getListFromDBWithId("111").subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe {
Log.e("list of students", it.toString())
})
I got an empty list, so I thought the problem was from the id, I tried to use the id that has been logged from the whole list and didn't work, I also used S to launch my sql query with the same id and I got the results.
Any help please?
Thanks
Is your AircraftEntity supposed to be StudentEntity? If yes (and I think it is, according to the rest of your code examples), then please update your question.
By default, Room uses the class name as the database table name, and I think it's case-sensitive, so your queries should have been "select * from StudentEntity". The better approach would be giving it a name explicitly:
#Entity(tableName = "students")
data class StudentEntity (
// ...
)
Then, your ProgramDAO would look like follow:
#Dao
interface ProgramDAO {
#Query("select * from students")
fun getStudents(): Single<List<StudentEntity>>
#Query("select * from students where classId = :classid")
fun getStudentsWithId(classid: String): Single<List<StudentEntity>>
}
You said: ... a room database that I'm populating from my api call
Where and how do you populate your database? I don't see any #Insert functions in your DAO, unless you just left them out from your code snippet. If your room DB is not populated, of course you will get no data.

Get HashMap<Model1, List<Model2>> in an MVVM+Repostiory+LiveData setting?

So I was working on this silly little app for practicing MVVM and Repository Pattern. I have two model classes at the moment. They are Category and SubCategory for which I have defined the following data classes:
#Entity(tableName = "categories")
data class Category(
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "id")
val id: Int,
#ColumnInfo(name = "name")
val name: String
) {
}
And
/**
* One to many Relationship from Category to SubCategory
*/
#Entity(
tableName = "sub_categories", foreignKeys = arrayOf(
ForeignKey(
entity = Category::class,
parentColumns = arrayOf("id"),
childColumns = arrayOf("category_id")
)
)
)
data class SubCategory(
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "id")
val id: Int,
#ColumnInfo(name = "name")
val name: String,
#ColumnInfo(name = "category_id")
val categoryId: Int
) {
}
As you can see, I have modeled the resources such that we will need categoryId to be passed to get SubCategories related to a Category.
Now I am pretty new with this MVVM and LiveData and Repository Pattern.
My Problem is that I am using an ExpandableListView to populate SubCategories under Categories and the Adapter for it requires a HashMap<Category, List<SubCategory> for it to display the expandable listview.
So my question is how do I get a HashMap<Category, List<SubCategory> from my database using an approach of db->dao->repository->viewmodel and wherever the adpater goes.
I suppose creating a separate repository like CategorySubCategoryRespository whereby I can do something like following is not going to help?:
class CategorySubCategoryRepository(
private val categoryDao: CategoryDao,
private val subCategoryDao: SubCategoryDao
) {
val allCategoriesSubCategories: LiveData<HashMap<Category, List<SubCategory>>>
get() {
val hashMap: HashMap<Category, List<SubCategory>> = hashMapOf()
for (category in categoryDao.getList()) {
hashMap[category] = subCategoryDao.getSubCategoriesListForCategory(category.id)
}
return hashMap
}
}
}
PS: I think I want to use LiveData wherever possible
So what I ended up doing was, in my CategorySubcategoryRepository I constructed the Hashmap from the CategoryDao and SubcategoryDao as follows:
class CategorySubCategoryRepository(
private val categoryDao: CategoryDao,
private val subCategoryDao: SubCategoryDao
) {
fun getHashMap(): LiveData<HashMap<Category, List<SubCategory>>> {
val data = MutableLiveData<HashMap<Category, List<SubCategory>>>()
val hashMap: HashMap<Category, List<SubCategory>> = hashMapOf()
Executors.newSingleThreadExecutor().execute {
for (category in categoryDao.getList()) {
hashMap[category] = subCategoryDao.getSubCategoriesListForCategory(category.id)
}
}
data.value = hashMap
return data
}
}
Then I used this in my viewmodel's init{} block like:
hashMap = categorySubCategoryRepository.getHashMap()
Then I observed it in my Fragment's onCreateView as:
myViewModel.hashMap.observe(this, Observer {
adapter.setCategoryList(it.keys.toList())
adapter.setCategorySubCategoriesMap(it)
elv_categories.setAdapter(adapter)
adapter.notifyDataSetChanged()
})
Do Comment if this is not the right thing to do. I am doing this only to increase my skills and would love to hear if there's a better way to go about things or if my approach is completely absurd.
Edit:
As per #SanlokLee's comment. The getHashMap function has been changed to:
fun getHashMap(): LiveData<HashMap<Category, List<SubCategory>>> {
val data = MutableLiveData<HashMap<Category, List<SubCategory>>>()
Executors.newSingleThreadExecutor().execute {
val hashMap: HashMap<Category, List<SubCategory>> = hashMapOf()
for (category in categoryDao.getList()) {
hashMap[category] = subCategoryDao.getSubCategoriesListForCategory(category.id)
}
data.postValue(hashMap)
}
return data
}

What is the benefit of using primarykey and references method in class jooq

I'm start the learn jooq. I have mssql server. I create some class the represent table on my server. But I don't understand what is the benefit when I was using getPrimaryKey and getReferences methods in my table class?
class User : TableImpl<Record>("users") {
companion object {
val USER = User()
}
val id: TableField<Record, Int> = createField("id", SQLDataType.INTEGER)
val name: TableField<Record, String> = createField("name", SQLDataType.NVARCHAR(50))
val countryId: TableField<Record, Short> = createField("country_id", SQLDataType.SMALLINT)
override fun getPrimaryKey(): UniqueKey<Record> = Internal.createUniqueKey(this, id)
override fun getReferences(): MutableList<ForeignKey<Record, *>> =
mutableListOf(Internal.createForeignKey(primaryKey, COUNTRY, COUNTRY.id))
}
class Country : TableImpl<Record>("country") {
companion object {
val COUNTRY = Country()
}
val id: TableField<Record, Short> = createField("id", SQLDataType.SMALLINT)
val name: TableField<Record, String> = createField("name", SQLDataType.NVARCHAR(100))
override fun getPrimaryKey(): UniqueKey<Record> =
Internal.createUniqueKey(this, id)
}
The generated meta data is a mix of stuff that's useful...
to you, the API user
to jOOQ, which can reflect on that meta data for a few internal features
For instance, in the case of getPrimaryKey(), that method helps with all sorts of CRUD related operations as you can see in the manual:
https://www.jooq.org/doc/latest/manual/sql-execution/crud-with-updatablerecords/simple-crud
If you're not using the code generator (which would generate all of these methods for you), then there is no need to add them to your classes. You could shorten them to this:
class User : TableImpl<Record>("users") {
companion object {
val USER = User()
}
val id: Field<Int> = createField("id", SQLDataType.INTEGER)
val name: Field<String> = createField("name", SQLDataType.NVARCHAR(50))
val countryId: Field<Short> = createField("country_id", SQLDataType.SMALLINT)
}
However, using the code generator is strongly recommended for a variety of advanced jOOQ features which you might not get, otherwise.

Cannot save data model that contains List<Model> with Room ORM Kotlin

I have a problem with Room ORM working on Kotlin. My task is having ability to save and get data models RouteTemplateModel, that contains list of addresses of type AddressModel and object of class RouteModel that contains title of the specific route. Here is my code:
AddressModel.kt
#Entity(foreignKeys = arrayOf(
ForeignKey(entity = RouteModel::class,
parentColumns = arrayOf("routeId"),
childColumns = arrayOf("parentId"))))
data class AddressModel(
#PrimaryKey(autoGenerate = true)
var addressId: Long,
var parentId: Long,
var street: String,
var house: String,
var entrance: String,
var title: String){
constructor(): this(0, 0, "", "", "", "")
}
RouteModel.kt
#Entity
data class RouteModel(
#PrimaryKey(autoGenerate = true)
var routeId: Long,
var title: String) {
constructor() : this(0, "")
}
Here is my simple models, I found in documentation of Room that for creating relations between models I need to use #ForeignKey and #Relation
So with code samples in doc and tutorials I create RouteTemplateModel that contains object of RouteModel and list of AddressModels. Here is the class
RouteTemplateModel
class RouteTemplateModel{
private var id: Long = 0
#Embedded
private var routeModel: RouteModel = RouteModel()
#Relation(parentColumn = "routeId", entityColumn = "parentId")
private var addressList: List<AddressModel> = listOf()
constructor()
constructor(id: Long, routeModel: RouteModel, title: String,
addressList: List<AddressModel>){
this.id = id
this.routeModel = routeModel
this.addressList = addressList
}
fun getId(): Long{
return id
}
fun getRouteModel(): RouteModel{
return routeModel
}
fun getAddressList(): List<AddressModel>{
return addressList
}
fun setId(id: Long){
this.id = id
}
fun setRouteModel(routeModel: RouteModel){
this.routeModel = routeModel
}
fun setAddressList(addressList: List<AddressModel>){
this.addressList = addressList
}
}
So what`s a problem? I am getting such errors:
Error:The columns returned by the query does not have the fields [id]
in com.innotech.webcab3kotlin.model.RouteTemplateModel even though
they are annotated as non-null or primitive. Columns returned by the
query: [routeId,title]
And
Error:Type of the parameter must be a class annotated with #Entity or
a collection/array of it.
It is a real problem, because if my trying to fix first error and annotate in RouteTemplateModel id variable to return this column too, I need annotate class as Entity (like in second error), but when I do it I am getting an error
Error:Entities cannot have relations.
Here is AppDatabase.kt
#Database(entities = arrayOf(RouteModel::class, AddressModel::class), version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun getRouteDao(): RouteDao
}
and RouteDao.kt
#Dao
interface RouteDao {
#Query("SELECT routeId, title FROM RouteModel")
fun getAll(): List<RouteTemplateModel>
#Insert
fun insertAll(vararg models: RouteTemplateModel)
#Delete
fun delete(model: RouteTemplateModel)
}
Thats really confusing. Please, help me)
Your "parentId" column is capable of holding long value only, make its type to "Text" then create a TypeConverter from "List" to String and vice a versa for reference please have a look at link .