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.
Related
I understand that the #Embedded annotation is used when we want to combine several fields which can then be represented into a single object. In the Android Developers documentation, within the one-to-one relationships section of the Define Relationships Between Objects document, we find this code:
#Entity
public class User {
#PrimaryKey public long userId;
public String name;
public int age;
}
#Entity
public class Library {
#PrimaryKey public long libraryId;
public long userOwnerId;
}
In the next section, about modeling the one-to-one relationships, there's this code which says:
public class UserAndLibrary {
#Embedded public User user;
#Relation(
parentColumn = "userId",
entityColumn = "userOwnerId"
)
public Library library;
}
What I don't understand is why are we using the #Embedded annotation just for the User class? The Library class also has several fields and we do need to combine them as well, right? Or is it because the #PrimaryKey field isn't considered as a separate field?
#Embedded annotation is used when we want to combine several fields which can then be represented into a single object
Yes, that's correct
But converse statement is not correct:
If you want to combine several fields into a single object you SHOULD ONLY use #Embedded annotation in Room
There is another method in Room how you can achieve this "combination" - with #Relation. But except "combining fields into a single object" #Relation makes some additional work - internally it changes your simplified DAO query:
select * from user
, so you don't need to write "JOIN" with another table. But this "additional" work makes sense ONLY for the second table, that's why first object - with #Embedded and the second - with #Relation.
You can, for example not to use #Relation in your example:
public class UserAndLibrary {
#Embedded public User user;
#Embedded public Library library;
}
But to get needed result in your query you have to explicitly use both tables and "JOIN" them or use "IN":
select * from user left join library on user.userId = library.userOwnerId
I am quite familiar with these kind of thing on Spring JPA but I can not make it work on Android. I post my code below so you can understand the question better. I have two classes and a third class that needs to contain objects of class 1 and 2. I know that the code for the third class is not correct, since Room does not support object references like that. If I save just the id-s of the objects as foreign keys I am not able to query after the results.
There must be some kind of nice solution for this problem. Thank you.
#Entity(tableName = "soup")
public class Soup {
#PrimaryKey(autoGenerate = true)
private long id;
private String name;
// getter and setters
}
#Entity(tableName = "main_course")
public class MainCourse {
#PrimaryKey(autoGenerate = true)
private long id;
private String name;
// getter and setters
}
#Entity(tableName = "menu")
public class Menu {
#PrimaryKey(autoGenerate = true)
private long id;
private Soup soupOptionOne;
private Soup soupOptionTwo;
private Soup soupOptionThree;
private MainCourse courseOptionOne;
private MainCourse courseOptionTwo;
private MainCourse courseOptionThree;
}
I've been using SugarDB for most of my projects in the past. It was easy to use and satisfied most of my requirements but since that project has been abandoned, decided to look at alternatives and Room seems like the best option.
However, some basic things are quite confusing in Room. My Object uses Gson to populate data from a webservice, and as such as links to other objects. As an example, consider the classes below:
#Entity
public class TestModel
{
#PrimaryKey(autoGenerate = true)
private int id;
private String name;
private String age;
private List<Book> issuedBooks;
}
public class Book
{
private String title;
private int ISBN;
}
Now if my first class is annotated as the Entity, will this automatically treat classes referenced inside it as entities as well?
If I save an object of TestModel, will it save the list of Books with it to the database?
I guess you can do it this way.
#Entity
public class TestModel {
#PrimaryKey
public int id; // TestModel id
public String name;
public String age;
}
#Entity
public class Book {
#PrimaryKey
public int id; // Book id
public int testModelId; // TestModel id
public String title;
public int ISBN;
}
public class TestModelWithBooks {
#Embedded
public TestModel testModel;
#Relation(parentColumn = "id", entityColumn = "testModelId", entity = Book.class)
public List<Book> books;
}
For their Dao, you can write it this way.
#Dao
public interface TestModelDao {
#Query("SELECT * FROM TestModel")
public List<TestModelWithBooks> loadTestModelsWithBooks();
}
will this automatically treat classes referenced inside it as entities as well?
No. In fact, I would expect your code to fail to compile. You would need to:
Make Book be an #Entity
Remove issuedBooks from TestModel
Set up a #ForeignKey relationship between Book and TestModel
If I save an object of TestModel, will it save the list of Books with it to the database?
No.
Room is not an ORM. Room is a thin object wrapper around SQLite. #Entity and #ForeignKey model the table structure. IMHO, the simplest way to think of Room as it being DTOs to the database. Your model objects that represent your object graph are not the entities, but instead are built from the entities. This is akin to how responses from a Web service (e.g., Retrofit) are DTOs to the server, and you may need to map from those objects to the "real" model objects that you want to use in the app.
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
How can we query Realm Database based on the RealmList as the member variable?
Let me further clarify the use case.
I have the following class:
public class Match extends RealmObject {
#PrimaryKey
#Expose
private String matchid;
#Expose
private RealmList<Team> Team = new RealmList<>();
}
And Team object looks like this:
public class Team extends RealmObject {
#PrimaryKey
#Expose
private String teamid;
}
I want to query all Match Objects in which teamid is 1 for example.
Is it possible? How can we write such query in Realm?
RealmResults<Match> results = realm.where(Match.class)
.equalTo("Team.teamid", 1).findAll();
More info on link queries: https://realm.io/docs/java/latest/#link-queries