Getting error on API level 23 & 24, Same Query is working fine on API level 29 & 30 and getting results.
Here are the entities(Removed the variables which are not used in Query for posting here)
#Entity
data class Activity(#PrimaryKey #ColumnInfo(name = "activity_id") val activityId: Int)
#Entity(tableName = "JobActivities", primaryKeys = ["activity_id", "job_id"])
data class JobActivity(
#ColumnInfo(name = "job_id")
val jobId: Int,
#ColumnInfo(name = "activity_id")
val activityId: Int,
)
#Entity(tableName = "LocationActivities")
data class LocationActivity(
#PrimaryKey
#ColumnInfo(name = "loc_act_id")
val locActId: String,
val active: Int?,
#ColumnInfo(name = "activity_id")
val activityId: Int?,
)
Query that i'm using
#Query("SELECT 'job' AS entity, l.activity_id , a.activity_name FROM LocationActivities l " +
"JOIN Activity a ON a.activity_id = l.activity_id WHERE loc_id = :locationId " +
"UNION SELECT 'loc' AS entity , j.activity_id , a.activity_name FROM JobActivities j " +
"JOIN Activity a ON a.activity_id = j.activity_id WHERE j.job_id = :jobId")
fun getActivities(locationId: String, jobId: Int): Flow<MutableList<ClassName>>
Related
This question already has answers here:
add unique constraint in room database to multiple column
(4 answers)
Closed 7 months ago.
I want to achieve unique audio_id for the id.
Here is my entity class
data class Members(
#PrimaryKey(autoGenerate = true) #ColumnInfo(name = "id") val id: Int?,
var title: String,
var artist: String,
var album: String,
#ColumnInfo(name = "audio_id") val audioId: Int,
val albumId: String
)
Tried this
#Entity(tableName = "playlist_members", indices = [Index(value = ["id","audio_id"], unique = true)])
not working :)
I've made a test example. So all work.
My entity
#Entity(tableName = "cards", indices = [Index(value = ["data"], unique = true)])
data class CardEntity(
#PrimaryKey(autoGenerate = true)
val id: Int = 0,
val data: String
)
My test
#Test
fun testRun() = runBlocking {
db.cardDAO().insert(CardEntity(data = "1"))
var exception = false
try {
db.cardDAO().insert(CardEntity(data = "1"))
} catch (e: SQLiteConstraintException) {
exception=true
}
db.cardDAO().insert(CardEntity(data = "2"))
Assert.assertTrue(exception)
Assert.assertEquals(db.cardDAO().getAll().first().size, 2 )
}
But you want to get unique audio_id for the id. Perhaps it the same like.
data class Members(
#PrimaryKey(autoGenerate = true) #ColumnInfo(name = "audio_id") val audioId = 0,
var title: String,
var artist: String,
var album: String,
val albumId: String
)
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 tried this but did not work
#Query("SELECT * FROM product_data_table WHERE product_end_date >= date('now') ORDER BY product_end_date ASC")
fun getAllProductsOrderByEndDate(): LiveData<List<Product>>
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
)
I am not sure how to use todays date in where clause
please suggest how to fix this
your help is much appreciated
Thanks
R
Store the end_date in Entity class as Long in Unix time
#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: Long // Changed the type from Date to Long
)
When inserting the product pass Date().time for end_date
Now when querying, get the Unix time of today and pass it as a parameter for the query function. Something like this:
#Query("SELECT * FROM product_data_table WHERE product_end_date >= :endDate")
fun getAllProductsOrderByEndDate(endDate: Long): List<Product>
I'm creating a small project with Room and three tables (jobs, tags, categories).
Essentially:
A job belongs to (or has) 1 and only category, but a job can have 0..N tags.
A category has 0..N jobs.
A tag has 0..N jobs.
I'm having some trouble trying to model all the data, especially when it comes to the relationships between the entities. More concretely, I have:
fun JobListing.toJobEntityList(): List<JobEntity> {
val jobEntityList = mutableListOf<JobEntity>()
this.jobs.take(50).forEach { job: Job ->
jobEntityList.add(
JobEntity(
jobId = job.id,
title = job.title,
url = job.url,
companyName = job.companyName,
jobType = job.jobType,
publicationDate = job.publicationDate,
relocation = job.candidateRequiredLocation,
salary = job.salary
)
)
}
return jobEntityList
}
This extension function is being called when I'm fetching the data from the network, so I can convert it to entities and store them in my DB.
I'm essentially creating a JobEntity, but a job should have 1 category and 0..N tags associated. The problem is that I don't know how to add that data related to the relationship between a job and its category and tags.
This is my JobEntity class:
#Entity(
tableName = "Jobs",
indices = [
Index("id", unique = true)
]
)
data class JobEntity(
#PrimaryKey #ColumnInfo(name = "id") val jobId: Int,
#ColumnInfo(name = "title") val title: String,
#ColumnInfo(name = "url") val url: String,
#ColumnInfo(name = "company_name") val companyName: String,
#ColumnInfo(name = "job_type") val jobType: String,
#ColumnInfo(name = "publication_date") val publicationDate: String,
#ColumnInfo(name = "candidate_required_location") val relocation: String,
#ColumnInfo(name = "salary") val salary: String
)
Thanks in advance!
Hi you should model your database like this:
Job_Category
Tags
Jobs (add category_id field and add 1 foreign key referencing to Category table)
Job_Tags (add tag_id, job_id fields and add 2 foreign keys referencing to Category and Jobs tables)
#Entity(tableName = "Category")
data class CategoryEntity(
#PrimaryKey #ColumnInfo(name = "id") val id: Int,
)
#Entity(tableName = "Tags")
data class TagEntity(
#PrimaryKey #ColumnInfo(name = "id") val id: Int,
)
#Entity(
tableName = "Jobs",
foreignKeys = [ForeignKey(entity = CategoryEntity::class, parentColumns = ["id"], childColumns = ["categoryid"])]
)
data class JobEntity(
#PrimaryKey #ColumnInfo(name = "id") val id: Int,
#ColumnInfo(name = "categoryid", index = true) val categoryid: Int,
// ... other fields
)
#Entity(
tableName = "JobTags",
foreignKeys = [
ForeignKey(entity = TagEntity::class, parentColumns = ["id"], childColumns = ["tagId"]),
ForeignKey(entity = JobEntity::class, parentColumns = ["id"], childColumns = ["jobId"]),
]
)
data class JobTagEntity(
#PrimaryKey #ColumnInfo(name = "id") val id: Int,
#ColumnInfo(name = "tagId", index = true) val tagId: Int,
#ColumnInfo(name = "jobId", index = true) val jobId: Int,
)
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>