I have three tables Notes, Tags and join table with foreign keys of Note and Tag called NoteTagJoin, but how can I return Note with all Tags as one response?
Here is query to get Note and Tags:
SELECT n.*,t.* FROM notes n INNER JOIN note_tag_join nt ON n.entryId = nt.noteId INNER JOIN tags t ON t.tagId = nt.tagId WHERE n.entryId =:noteId
And here is response class which has to hold note and list of tags:
data class NoteResponse(
#Embedded
var note: Note? = null,
#Relation(parentColumn = "entryId", entityColumn = "tagId", entity = Tag::class)
var tags: List<Tag>? = null
)
But tags list is empty on response just note is there, I know for sure that Tags and Note exists in db and Join table has right foreign keys because all other queries works so my guess is that Query is wrong or NoteResponse class is wrong because I use annotation #Relation which I don't need, but if I don't add #Relation annotation on tags it throws error that room doesn't know what is this list so how to do it? I can't find any references for this, documentation only mentions embedding one class in POJO but no examples for Lists and all similar posts talks only about inserting list.
please see my realization of many-to-many relationship CinemaActorJoinDao
You can instead my code , replace with your , if you have any question , i will try ask to you :)
Related
I've found literally 0 articles/threads about this error on the internet so I'm absolutely clueless, so here it goes.
I have a class A and a class B.
class A is having an ArrayList of class B instances like this:
#Entity
class A {
#PrimaryKey
var id = 0
var listOfB: ArrayList<B>
}
And here it goes the B class:
#Entity
class B {
#PrimaryKey
var id = 0
var specificDate: Date? = null
}
Whenever I try to run the project I get the following error message:
Cannot use unbound fields in entities.
Which points exactly to the ArrayList of B instances inside the A class.
What may be causing this?
An Entity has two purposes:
It defines the columns of a table in the database.
An instance of the entity represents one row of an element in that database, which can be given to you as a query result, or you can pass to Room to add or edit a row in the corresponding table.
SQL/SQLite doesn't have the concept of a table column where the type is another table or list of rows from another table, so what you're defining doesn't make sense. (Incidentally, you cannot use Lists of any type for a column type in a table. You can only use primitive type classes in an Entity class since that's all that SQL supports.)
Instead, you must define a relationship between your two tables. In this case, you can remove the list property from your class A. I'm not sure if you're trying to define a one-to-many or many-to-many relationship, but you can look at the Room documentation here for an example of how to set up relationships.
Basically, if a B can only be a member of a single A at a time, B should reference an A row ID in one of its columns, and you have a one-to-many relationship. Room will let you create a third data class (not an entity) to define the relationship in a natural way that looks similar to your example class A and can be returned in queries.
If B can belong to multiple different A's, then you have a many-to-many relationship, which is more complicated. A third table (Entity class) has to be defined to link the relationships together.
I need to migrate from Sqlite database to room in my application, but before migrating i have some doubts regrading room database i have searched through many sites but i have not satisfied with the solution.
My table schema will be changing frequently through API calls, is it possible in room ?
We need entities to map Column Name with entity properties, Since my table schema changes frequently how do i create the entity ?
Is it possible to map the multiple columns to single field property in entity, like say
Table A has three columns COL_A,COL_B,COL_C
#Entity
class TableA{
#ColumnInfo("COL_A")
val columnA : String
#ColumnInfo("COL_B,COL_C")
val columns : Map<String,String>
}
Is it possible to create entity like above in room?
Can anyone clear the above doubts ?
In an app I'm working on, I need to very simply fetch data from a Room database. There are relations involved. Everything was working perfectly with simple queries returning LiveData, however, the size of the data that needs to be retrieved grew much larger than expected and it also contains blobs (images), which can make the query very slow. I've resolved to using the Paging library, implemented as follows, but for some reason the #relation annotation simply doesn't work anymore.
The entity fetched is a DTO, looks basically like this:
data class EntityOtherAnotherDTO(
var id: Long? = null,
var name: String? = null,
...,
#Relation(parentColumn = "id", entityColumn = "entity_id", entity = OtherEntity::class)
var others: List<OtherEntity>,
#Relation(parentColumn = "id", entityColumn = "entity_id", entity = AnotherEntity::class)
var anothers: List<AnotherEntity>
)
The query:
#Query("SELECT * FROM other
JOIN entity ON entity.id = other.entity_id
JOIN another ON entity.id = another.entity_id
WHERE entity.deleted = 0
ORDER BY
CASE WHEN other.some_column IS NULL THEN 1 ELSE 0 END,
other.some_column ASC,
entity.some_other_column DESC")
fun getAllEntityOtherAnotherDTOs(): DataSource.Factory<Int, EntityOtherAnotherDTO>
When the query was like this: fun getAllEntityOtherAnotherDTOs(): LiveData<List<EntityOtherAnotherDTO>> everything worked just fine. The results were ordered as required and all data was fetched, including the lists annotated with #relation. But after changing the return type to DataSource.Factory and of course implementing a paging adapter, the relations return empty.
The ordering still works perfectly, the query appears to be working exactly as before, the paging also works, but the data is simply missing. All the columns in the entity table are there (name, some_other_column etc.), the relations are the only but major problem.
(I can provide further details about the paging implementation, if that's of any relevance.)
Turns out this is an issue in Room which can happen even when you don't use the Paging library, given a large-ish (hundreds of results+) query.
There is no solution, but there is a workaround for 1:1 relations: using #embedded instead of #relation. That can however complicate things through the need of setting a prefix and enumerating all columns in the query and giving them aliases. That's pain but such is life. Room sucks.
Or if the joined entity doesn't have too many columns and there aren't any duplicate names, it works just as fine to copy those columns/properties in the DTO that is returned by the query.
So I have two tables City and Street I wrote query to return City and its streets with one query response looks like this
1 City1
1 Street1
2 Street2
3 Street3
and I have POJO class for this response:
data class CityResponse(var city: City, var streets: List<Street>)
But I can't compile because it throws error:
error: Cannot figure out how to read this field from cursor private java.util.List<Street> streets
How can I write this response data class that room would understand what do I mean with variable streets: List<Street>
In this case used joins query and make one common pojo class that give both details. then make query like below ..
#Query("SELECT * FROM Student s LEFT JOIN BookIssue b ON s.StudentId =b.StudentId")
List<JoinData> getJoinData();
you can also implement inner join and others joins but make one single pojo that give both table record.
and also one more way first find city and make for loop and find based on city name into street and getting street data.
I tried joining the three entities using the example that GreenDao provides here but it gives me an error on the last line under the leadTopersonJoin parameter that says "Type Mismatch, expected Join<*, Lead> found Join< Lead, Person> and I can't figure out how to fix it.
var daoSession: DaoSession = Application.getInstance().daoSession
var queryBuilderLead: QueryBuilder<Lead> = daoSession.leadDao.queryBuilder()
var leadToPersonJoin: Join<Lead, Person> = queryBuilderLead.join(LeadDao.Properties.LeadPersonId, Person::class.java, PersonDao.Properties.PersonLeadId)
var personToAddresJoin = queryBuilderLead.join(leadToPersonJoin, PersonDao.Properties.PersonAddressId, Address::class.java, AddressDao.Properties.AddressPersonId)
What raw Sql can I use to join the three tables? or alternatively what am I doing wrong in the greenDao Query?