Insert into multiple tables using Room Persistence Library - android

It's the first time I am using Room. I have a class called:
#Entity(tableName = "users")
class User{
#PrimaryKey
#ColumnInfo(name = "id")
#SerializedName("id")
String id;
#ColumnInfo(name = "name")
#SerializedName("name")
String name;
#SerializedName("shift")
#Ignore
List<Shift> shifts;
}
#Entity(tableName = "shifts")
class Shift{
#PrimaryKey
#ColumnInfo(name = "id")
#SerializedName("id")
String id;
#ColumnInfo(name = "start_time")
#SerializedName("start_time")
String startTime;
#ColumnInfo(name = "end_time")
#SerializedName("end_time")
String endTime;
}
I want these two to be seperate tables in the database, hence I cannot user #Embedded annotation, as it will create a single table using all field as columns. I am using the above User class to store json reponse from the server as well, where I get the user and shift details information in a json object.
Is there any way I can insert the Shift details in shifts table as soon as I insert the User details in the users table ? I initially thought this will be handled using #Embeded but that will create shift table columns in the user table which I do not want.
Can someone help me as to how I am suppose to handle this in Room Persistence Library. Similar I will have to do for delete as well.
Thanks

Is there any way I can insert the Shift details in shifts table as soon as I insert the User details in the users table ?
Create your own DAO #Transaction method that calls inserts for User and Shift.
Similar I will have to do for delete as well.
If you fix your Shift class, such that it has a #ForeignKey relationship to User with the appropriate cascade-delete option, deleting a User will delete its Shift rows as well. In your current implementation, User and Shift are unrelated.

Related

andorid room inner join one column from table

This is my table :
#Parcelize
#Entity(tableName = "profile")
data class Profile(
#SerializedName("id") #PrimaryKey var id:Long,
#SerializedName("name") var name :String?,
#TypeConverters(UserConverter::class)
#NotNull
#SerializedName("users") var users :List<Long>?
):Parcelable
and this is my second table :
#Parcelize
#Entity(tableName = "user")
data class User(
#PrimaryKey
#SerializedName("id") var id: Long,
#SerializedName("name") var name: String
) : Parcelable
and I want to get this object :
data class ProfileWithUsersName(
val profile: Profile,
val usersName: List<String>?
)
to get this list of objects I do this :
fun getProfiles() :List<ProfileWithUsersName>{
val arrayListTemp = arrayListOf<ProfileWithUsersName>()
val profiles = profileDao.getProfiles()
for(profile in profiles){
if(profile.users != null) {
arrayListTemp.add(
ProfileWithUsersName(
profile,
userDao.getUsersNameByIds(profile.users!!)
)
)
}else{
ProfileWithUsersName(
profile,
null
)
}
}
return arrayListTemp.toList()
}
it is any changes to do this on one query ?
it could be something like this
#Dao
abstract class ProfileDao {
companion object {
const val QUERY = "SELECT * FROM profile " +
"INNER JOIN user " +
`your condition`
}
#Query(QUERY)
abstract fun getCurrentStep(): List<ProfileWithUsersName>?
}
}
and your profile should be something like this
data class ProfileWithUsersName(
#Embedded val profile: Profile,
#Embedded val usersName: List<String>?
)
May be that would not be full answer, but why not to get partly answer?
Notes to your tables' structure
It's not so optimal and it would be better not to hold information about users having exact profile in Profile class (better option - to remove this into another table). But let it be.
With no changes to tables' structure I think your decision with nested queries could be better if you call the function "userDao.getUsersNameByIds(profile.users!!)" just once (but for that you should change logic a little bit). But I think your tables are not too big to invest time into such optimisations.
As for "do this in one query"
Actually I think that there are some chances to succeed in that, but honestly I don't think it worth of it and that query would be faster or more elegant than loops. But it could be a challenge for somebody :)
Main problem here - is field "users" in your entity "Profile". In SQLite I guess you save it as a String (with the help of UserConverter). For example, if you have list of ids: [111, 222, 333] in SQLite they will be saved as TEXT "111,222,333". So on next step we must somehow JOIN table with such a field an a table, that has INTEGERS 111|222|333.
That could be done only with casting INTEGER To TEXT and then JOIN tables on condition - casted_value_from_second_table LIKE ["%," + value_from_first_table + ",%]" in pseudocode. Maybe that requires some changes to your TypeConverter. Even if it will be successful, JOIN tables with "LIKE" is not best practice.
Conclusions:
Without changes to tables' structures and if your tables are not very big I think way how you do now - is acceptable. With "one query" (again, with no changes to db tables' structure) it's not regular task, there are several problems that are needed to be solved experimentally - I don't think it worth of it.
P.S. Maybe I don't see some obvious decision, so it's just my personal opinion :)

Room database: What is Index specific columns (indices and #Index) and how to use it?

I was referring Index specific columns of Room Database.
Below is some example code is written here https://developer.android.com/training/data-storage/room/defining-data#column-indexing
Example Code-1:
#Entity(indices = {#Index("name"),
#Index(value = {"last_name", "address"})})
public class User {
#PrimaryKey
public int id;
public String firstName;
public String address;
#ColumnInfo(name = "last_name")
public String lastName;
#Ignore
Bitmap picture;
}
Example Code-2:
#Entity(indices = {#Index(value = {"first_name", "last_name"},
unique = true)})
public class User {
#PrimaryKey
public int id;
#ColumnInfo(name = "first_name")
public String firstName;
#ColumnInfo(name = "last_name")
public String lastName;
#Ignore
Bitmap picture;
}
This is described in room documentation by android,
I have used indices for the uniqueness of column but what does above code means can anyone explain it?
Q1: What is the use of indices and #Index?
Q2: What is the difference between #Index("name") and #Index(value = {"last_name", "address"})?
Bit late on the answer. but hope so it will help someone.
Q1: What is the use of indices and #Index?
Indices: Can contain the list of indices on the table. whereas #Index is used to define an index.
For example:
#Entity(indices = {
#Index("FirstIndex"),#Index(value="last_name",unique = true),
#Index("SecondIndex"),#Index(value="first_name", unique = true)
})
As you can see, i have defined two indexes in this example which are separated by coma. Here "FirstIndex" and "SecondIndex" are the name of indexes. If i don't define the name of indexes (as you have quote in your example) then Room will set it to the list of columns joined by '' and prefixed by "index${tableName}". So if you have a table with name "Foo" and with an index of {"bar", "baz"}, generated index name will be "index_Foo_bar_baz".
Q2: What is the difference between #Index("name") and #Index(value = {"last_name", "address"})?
#index("name") //syntax to give name of index.
#index(value=last_name", "address") //Syntax to define, which column(s) need to be indexed
Indexing is the process of adding indexes which are used to quickly locate data without having to search every row in a database table every time the database table is queried or accessed.
Room supports indexing certain fields or indexing group of fields using indices property to speed up the queries. you can check the below link for further knowledge.
https://proandroiddev.com/exploring-room-architecture-component-the-extras-cf3f0259ceed
In Kotlin actually the syntax is a bit different:
#Entity(indices = [Index(value = ["last_name", "address"])])
data class User(
#PrimaryKey val id: Int,
val firstName: String?,
val address: String?,
#ColumnInfo(name = "last_name") val lastName: String?,
#Ignore val picture: Bitmap?
)
This is the Room Reference document with this and lots of other info: RoomDb Reference

Android Room Relationships -- List of Foreign Keys

I'm having trouble understanding how to set up my Room relationships. I haven't found an example analogous to mine anywhere online.
I have a User object (I've left out getters and setters):
#Entity
public class User {
#PrimaryKey
#NonNull
private String userId;
#ColumnInfo
private String name;
#ColumnInfo
private List<Long> seminarsAttended;
}
and a Seminar object:
#Entity
public class Seminar {
#PrimaryKey
private Long seminarId;
#ColumnInfo
private String topic;
....}
The list "seminarsAttended" in the User object is a list of seminarIds. The User class is linked up to a Retrofit call, so I can't modify the class to instead hold a list of Seminar objects.
How can I model this relationship in Room, such that the seminarIds in the User's seminarsAttended list are correlated with their corresponding Seminar in the seminars.db table?
It looks like the list of seminarsAttended should be a list of foreign keys into the seminars.db table, but I'm having trouble finding an example.

Room query with column alias returning null

I've been struggling with this and I haven't found a solution.
Let's say I have this sample entity:
#Entity (tableName="test")
public class Test{
#PrimaryKey(autoGenerate = true)
#ColumnInfo(name = "id")
private long id;
#ColumnInfo(name = "field1")
#NonNull
private double field1;
#Ignore
#ColumnInfo(name = "queryField")
private transient String queryField;
}
So basically my table has id and field1 while queryField is not a column table but it's used for instance on screens to show extra details from another table.
Then in my DAO
...
#Query("Select a.id, a.field1, b.column as queryField
"from test a inner join some_table on..." +
"where a.id=:someId" +
"order by i.name ASC")
LiveData<List<Test>> get(long someId);
....
So running someting like this, and the query result while it contains test.id and test.field1 info it does not fill the queryField property which remains null.
#Entity does not allow this kind of queries? Do I need to generate another class to add the new column? I'd like to mix Entities and Pojos in the project to keep things simple.

How to handle Object References in Entity?

I have the following structure to save to app database:
#Entity
public class Project{
#primaryKey
String id;
String name;
[...]
Country country;
[...]
}
And my Country Entity looks like the following:
#Entity
public class Country {
#PrimaryKey
private String id;
private String name;
private String pk;
}
Now to my Question: How do I make Room know the Relation between Country and Project Entity?
Room can not have nested entities, you can embedd POJO classes in an entity but it will get flattened into a single table or if you want Country as an entity then you'll have to store county_id in Project entity and index it as foreign key.
More on Embedded fields: https://developer.android.com/reference/android/arch/persistence/room/Embedded.html
More on Foreign key: https://developer.android.com/reference/android/arch/persistence/room/ForeignKey.html
Please refer the official documentation
https://developer.android.com/reference/android/arch/persistence/room/Relation.html

Categories

Resources