Given that I have 3 entities, Order contains list of LineItem, each LineItem will associates with one Product by productId.
The problem that when I get data from OrderDao, it returns null for the product field, but in the lineItem field, it has data. While I can data with ProductWithLineItem.
Already tried a lot of work arounds but it does not work.
Here is my code for entities and dao
Entities
#Entity(tableName = DataConstant.ORDER_TABLE)
data class Order(
#PrimaryKey
#ColumnInfo(name = "orderId")
val id: String,
#ColumnInfo(name = "status")
var status: String
)
#Entity(tableName = DataConstant.LINE_ITEM_TABLE)
data class LineItem(
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "lineItemId")
val id: Long,
#ColumnInfo(name = "productId")
val productId: String,
#ColumnInfo(name = "orderId")
val orderId: String,
#ColumnInfo(name = "quantity")
var quantity: Int,
#ColumnInfo(name = "subtotal")
var subtotal: Double
)
#Entity(tableName = DataConstant.PRODUCT_TABLE)
data class Product(
#PrimaryKey
#NonNull
#ColumnInfo(name = "productId")
val id: String,
#ColumnInfo(name = "name")
var name: String?,
#ColumnInfo(name = "description")
var description: String?,
#ColumnInfo(name = "price")
var price: Double?,
#ColumnInfo(name = "image")
var image: String?,
)
Relations POJOs
data class ProductAndLineItem(
#Embedded val lineItem: LineItem?,
#Relation(
parentColumn = "productId",
entityColumn = "productId"
)
val product: Product?
)
data class OrderWithLineItems(
#Embedded var order: Order,
#Relation(
parentColumn = "orderId",
entityColumn = "orderId",
entity = LineItem::class
)
val lineItemList: List<ProductAndLineItem>
)
Dao
#Dao
interface OrderDao {
#Transaction
#Query("SELECT * FROM `${DataConstant.ORDER_TABLE}` WHERE orderId = :id")
fun getById(id: String): Flow<OrderWithLineItems>
}
Result after running with Dao
Result after running query
Here is my code for entities and dao
You code appears to be fine, with the exception of returning a Flow, testing, using your code, but on the main thread using List (and no WHERE clause) i.e the Dao being :-
#Query("SELECT * FROM ${DataConstant.ORDER_TABLE}")
#Transaction
abstract fun getOrderWithLineItemsAndWithProduct(): List<OrderWithLineItems>
Results in :-
The data being loaded/tested using :-
db = TheDatabase.getInstance(this)
orderDao = db.getOrderDao()
orderDao.clearAll()
orderDao.insert(Product("product1","P1","desc1",10.01,"image1"))
orderDao.insert(Product("product2","P2","desc2",10.02,"image2"))
orderDao.insert(Product("product3","P3","desc3",10.03,"image3"))
orderDao.insert(Product("product4","P4","desc4",10.04,"image4"))
orderDao.insert(Product("","","",0.0,""))
val o1 = orderDao.insert(Order("Order1","initiaited"))
val o2 = orderDao.insert(Order("Order2","finalised")) // Empty aka no List Items
val o1l1 = orderDao.insert(LineItem(10,"product3","Order1",1,10.01))
val o1l2 = orderDao.insert(LineItem(20,"product4","Order1",2,20.08))
val o1l3 = orderDao.insert(LineItem(30,"","Order1",3,30.09))
val o1l4 = orderDao.insert(LineItem(40,"","x",1,10.01))
//val o1l3 = orderDao.insert(LineItem(30,"no such product id","Order1",10,0.0))
// exception whilst trying to extract if not commented out at test = ....
val TAG = "ORDERINFO"
val test = orderDao.getOrderWithLineItemsAndWithProduct()
for(owl: OrderWithLineItems in orderDao.getOrderWithLineItemsAndWithProduct()) {
Log.d(TAG,"Order is ${owl.order.id} status is ${owl.order.status}")
for(pal: ProductAndLineItem in owl.lineItemList) {
Log.d(TAG,"\tLine Item is ${pal.lineItem.id} " +
"for Order ${pal.lineItem.orderId} " +
"for ProductID ${pal.lineItem.productId} " +
"Quantity=${pal.lineItem.quantity} " +
"Product description is ${pal.product.description} Product Image is ${pal.product.image} Price is ${pal.product.price}")
}
}
As such I believe the issue might be that for some reason the Flow is detecting when the first query has completed but prior to the underlying queries.
That is when using #Relation the core objects (Order's) are extracted via the query and the core objects created then the related objects are extracted by a another query and used to build ALL the related objects as a List (unless just the one when it doesn't have to be a list). So prior to this underlying query the core object will have a null or an empty list for the underlying objects. Of course with a hierarchy of #Relations then this is replicated along/down the hierarchy.
I would suggest temporarily adding .allowMainThreadQueires to the databaseBuilder and using a List<OrderWithLineItems> or just a sole OrderWithLineItems. If using this then you get the Product(s) then the issue is with the Flow (which is what I suspect).
Hi I have a query where I order the list of products based on the product_end_date. I want to get only the list of products whose end date is greater than or equal to today,how can i do that in Room
here is my query
#Query("SELECT * FROM product_data_table ORDER BY product_end_date ASC")
fun getAllProductsOrderByEndDate(): LiveData<List<Product>>
I want to do
#Query("SELECT * FROM product_data_table WHERE product_end_date >= date('now') ORDER BY product_end_date ASC")
fun getAllProductsOrderByEndDate(): LiveData<List<Product>>
I am not sure how to use todays date in where clause
please suggest
Edit
Entity
#Entity(tableName = "product_data_table")
data class Product(
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "product_id")
var id: Int,
#ColumnInfo(name = "product_name")
var name: String,
#ColumnInfo(name = "product_catagory")
var catagory: String,
#ColumnInfo(name = "product_end_date")
var end_date: Date
)
Thanks
R
#Query("SELECT * from product_data_table WHERE DATE(product_end_date) >= DATE('now') ")
fun getAllProductsOrderByEndDate(): LiveData<List<Product>>
I have two tables sites and groups with the data classes like that
#Entity(tableName = "sites")
data class Site(
#PrimaryKey
#ColumnInfo(name = "site_id")
val siteId: Int,
#ColumnInfo(name = "description", defaultValue = "")
val description: String
)
#Entity(tableName = "groups")
data class Group(
#PrimaryKey
#ColumnInfo(name = "group_id")
var groupId: Int,
#ColumnInfo(name = "site_id")
val siteId: Int,
#ColumnInfo(name = "description", defaultValue = "")
val description: String
)
so as we can see each Site has a list of Groups.
What i want is, given a site_id and group_id how can i get a result pojo like that
class SiteGroup {
#Embedded
var site: Site? = null
#Relation(parentColumn = "site_id", entityColumn = "site_id", entity = Group::class)
var groups: Group? = null
}
I have tried the below
#Query("""Select * from sites
inner join groups on groups.site_id = :siteId
where site_id = :siteId and groups.group_id = :groupId
""")
fun getByIdWithGroup(siteId: Int, groupId: Int): LiveData<SiteGroup>
but i get the following exception on build time
error: There is a problem with the query: [SQLITE_ERROR] SQL error or missing database (ambiguous column name: site_id)
public abstract androidx.lifecycle.LiveData<com.example.model.entities.pojos.SiteGroup> getByIdWithGroups(int siteId, int groupId)
Incremental annotation processing requested, but support is disabled because the following processors are not incremental: androidx.room.RoomProcessor (DYNAMIC).
Problem solved. The problem was the where site_id.
The correct way is
#Query("""Select * from sites
inner join groups on groups.site_id = :siteId
where sites.site_id = :siteId and groups.group_id = :groupId
""")
fun getByIdWithGroup(siteId: Int, groupId: Int): LiveData<SiteGroup>
I use Room framework in an Android Studio project.
At present, I need to get the records of MVoice and sort the query result by createdDate desc, createdDate asc, name desc or name asc.
So I write the following code, but it's too complex, I think maybe it can be simple, such as passing field as paramter, I don't know how to do, could you tell me?
Code
interface DBVoiceDao{
#Query("SELECT * FROM voice_table ORDER BY createdDate desc")
fun listVoiceDateDesc():LiveData<List<MVoice>>
#Query("SELECT * FROM voice_table ORDER BY createdDate asc")
fun listVoiceDateAsc():LiveData<List<MVoice>>
#Query("SELECT * FROM voice_table ORDER BY name desc")
fun listVoiceNameDesc():LiveData<List<MVoice>>
#Query("SELECT * FROM voice_table ORDER BY name asc")
fun listVoiceNameAsc():LiveData<List<MVoice>>
}
data class MVoice(
#PrimaryKey (autoGenerate = true) #ColumnInfo(name = "id") var id: Int = 0,
var name: String = "",
var path: String = "",
var createdDate: Calendar = Calendar.getInstance(),
var isStar: Boolean = false,
var description: String = "",
var translation: String = ""
): Parcelable {}
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>
}