I go through SQL query other solution. i am not able to find suitable solutions for my problem.
In My project, i have the insert data into the table. I have to follow some steps
Step1:- I have to check data through a primary key that the data is available or not.
Step 2: if data is available then I have to update that data and return response code. if not I have to go step 3
Step 3: if data is not in the table then insert data into it and return code.
I am using Room Library. i am confused how to write in #Dao to perform that task.
Thanks in advance
Android Architecture Components introduced Android Room Persistence Library which is best for sqlite android database handling. Entity in Room Persistence represents a database table and Dao is where we define database interactions. Example
#Entity
public class Trail {
public #PrimaryKey String id;
public String name;
public double kilometers;
public int difficulty;
}
possible Dao for this table will be
#Dao
public interface TrailDao {
#Insert(onConflict = IGNORE)
void insertTrail(Trail trail);
#Query("SELECT * FROM Trail")
List<Trail> findAllTrails();
#Update(onConflict = REPLACE)
void updateTrail(Trail trail);
#Query("DELETE FROM Trail")
void deleteAll();
}
Further you need to provide RoomDatabase implementation, Example
#Database(entities = {Trail.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
public abstract TrailDao trailDao();
public static AppDatabase getInMemoryDatabase(Context context) {
if (INSTANCE == null) {
INSTANCE =
Room.inMemoryDatabaseBuilder(context.getApplicationContext(), AppDatabase.class)
.allowMainThreadQueries()
.build();
}
return INSTANCE;
}
public static void destroyInstance() {
INSTANCE = null;
}
}
Use It like
AppDatabase. getInMemoryDatabase(context).trailDao().findAllTrails();
Related
I am not familiar with Room Database. I want to clear the data from some tables when I click on button. I have the similar code in IOS but I am not sure where I have to write this method and call this delete function and how to access the tables. Can anyone help me on this in android.
IOS code:
class ApplicationResetManager: NSObject {
static let shared: ApplicationResetManager = ApplicationResetManager()
var cloSuccess:((_ isSuccessfull: Bool)->Void)?
func clearAllData(completion: (Bool) -> Void) {
let isSyncGoingOn = ApplicationManager.shared.isSyncGoingOn
if let currentUser = ApplicationManager.shared.currentUser, currentUser.id! > 0, isSyncGoingOn == false {
let dbQueue = DatabaseManager.shared.dbQueue!
do {
// 4. Access the database
try dbQueue.inTransaction { db in
do {
try UserLocations.deleteAll(db)
try LineLayoutEquipment.deleteAll(db)
try LineLayout.deleteAll(db)
try Survey.deleteAll(db)
try HealthCheck.deleteAll(db)
try HealthCheckData.deleteAll(db)
try ActionItem.deleteAll(db)
try Equipments.deleteAll(db)
try EquipmentIndustry.deleteAll(db)
try Comments.deleteAll(db)
try PlantAreas.deleteAll(db)
try PlantAreasIndustrys.deleteAll(db)
try Applications.deleteAll(db)
try ApplicationsIndustrys.deleteAll(db)
try SurveyLineLevel.deleteAll(db)
try HealthCheckLineLevel.deleteAll(db)
try ActionItemLineLevel.deleteAll(db)
try ActionItemLineLvlComments.deleteAll(db)
UserDefaults.standard.set([], forKey: arr_selected_company)
ApplicationManager.shared.currentUser.defaultCompanyId = nil
completion(true)
return .commit
} catch {
completion(false)
return .rollback
}
}
} catch {
completion(false)
}
} else {
print("Sync is already in progress")
}
}
}
If using Room you would have
#Entity annotated classes (the tables),
a single #Database annotated class per database (very probably just the 1) that:-
1.describes the database (list of entities (i.e. tables aka #Entity annotated class(es)) via the entities parameter)
provides abstract methods for obtaining the #Dao annotated (interface(s) or abstract class(es))
One or more #Dao annotated interfaces and/or abstract classes which
detail the convenience methods (#Insert, #Delete, #Update) and #Query methods.
As you appear to want to do many things in a single transaction, the you would want a method that invokes those many actions.
An interface cannot have methods with functions, therefore you would need an #Dao annotated class.
The actual, do many things method is a little bit of a trick.
You first of all have an #Transaction annotation. As room doesn't appear to consider this annotation unless you are using one of the annotations (and the only one that can be tailored is #Query), then you tell Room to run a query that does nothing i.e. use #Query("").
The you define the method with the body that can invoke other methods in the #Dao annotated abstract class.
So you your code could be along the lines of:-
#Dao
abstract class MyDoitAllStuffDao {
#Query("DELETE FROM userLocations") /* no WHERE clauses = delete all rows. TO BE USED IN DO IT ALL METHOD*/
int deleteAllUserLocations();
#Query("DELETE FROM linelayoutequipment");
int deleteAllLineLayoutEquipment();
....
#Transaction
#Query("") /* trick room into think it is doing something */
void /* or some useful return type */ doLotsOfThingsInASingleTransaction() {
.... if you want to do preparotory stuff
int deleteAllUserLocations_count = deleteAllUserLocations();
int deleteAllLineLayout_count = deleteAllLineLayoutEquipment();
.... etc
}
}
Then somewhere in you code you get an instance #Database abstract class with the RoomDatabase built and then retrieve and then invoke the appropriate method (doLotsOfThinsInASingleTransaction) after getting the respective #Dao annotated interface/class instance via the abstract method in the #Database annotated abstract class.
Here's an example (not run but compiled successfully)
A few #Entity annotated classes (very basic as it's not about the complexity/design of tables):-
#Entity
class UserLocations {
#PrimaryKey Long id=null;
String user_name;
}
#Entity
class LineLayoutEquipment {
#PrimaryKey Long id=null;
String lle_name;
}
obviously your classes will very likely differ, that is not relevant
The #Dao annotated abstract class (rather than the more typical interface (abstract class is more flexible due to methods with bodies)):-
#Dao
abstract class MyDoitAllStuffDao {
#Query("DELETE FROM userLocations")
abstract void deleteAllUserLocations();
#Query("DELETE FROM linelayoutequipment")
abstract void deleteAllLineLayoutEquipment();
#Transaction
#Query("")
void doLotsOfThingsInASingleTransaction() {
deleteAllUserLocations();
deleteAllLineLayoutEquipment();
}
}
I typically code these after the #Database annotated class, but makes more sense to include it before as the #Database annotated class, when complete requires the #Dao annotated class(es)
The #Database annotated abstract class (singleton):-
#Database(
entities = {UserLocations.class,LineLayoutEquipment.class},
exportSchema = false,
version = 1
)
abstract class TheDatabase extends RoomDatabase {
abstract MyDoitAllStuffDao getMyDoitAllStuffDao();
private static TheDatabase INSTANCE;
static TheDatabase getInstance(Context context) {
if (INSTANCE==null) {
return Room.databaseBuilder(context,TheDatabase.class,"the_database.db")
.build();
}
return INSTANCE;
}
}
Finally using the above in activity code e.g. :-
public class MainActivity extends AppCompatActivity {
TheDatabase db;
MyDoitAllStuffDao dao;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
db = TheDatabase.getInstance(this);
dao = db.getMyDoitAllStuffDao();
dao.doLotsOfThingsInASingleTransaction();
}
}
So all you need to do is ensure you have instantiated the db and dao with scope for the Listener and use the last line (off the main thread though if following conventions).
In my android app, I am storing data in database using Room Database library.I can store and get data in a single session.There is no problem in that. The problem is when I close the app and open again I am not getting the data stored in the local database.Those data are deleted.
I've searched in google and some of them said create room data database instance using databaseBuilder.But I am using that only.but I am getting this error.
This is my instance initialization.
This is my AppDtabase class ;
#Database(entities = {SelectedBuilding.class}, exportSchema =true, version=2)
public abstract class AppDatabase extends RoomDatabase {
private static AppDatabase INSTANCE;
public abstract SelectedBuildingDao myDao();
public static AppDatabase getAppDatabase(Context context){
if (INSTANCE==null){
INSTANCE= Room.databaseBuilder(context.getApplicationContext(),AppDatabase.class,"Selected_buildings")
.addMigrations(MIGRATION_1_2)
.build();
}
return INSTANCE;
}
public static void destroyInstance(){
INSTANCE=null;
}
static final Migration MIGRATION_1_2 = new Migration(1, 2) {
#Override
public void migrate(SupportSQLiteDatabase database) {
database.execSQL("ALTER TABLE selected_building ADD COLUMN Building_Id TEXT");
}
};
}
INSTANCE= Room.databaseBuilder(context.getApplicationContext(),AppDatabase.class,"Selected_area").build();
Can anyone help me to solve this issue?
Thanks in Advance.
I've set up a room database with 3 columns (title, descriptions, genre). I want to query the genre column with a user-specified genre(comedy, horror, etc) and return the results.
DAO Interface
I want the Query to only retrieve the entries where the genre matches the genre selected by the user.
#Dao
public interface MovieDAO {
#Query SELECT * FROM movie_table WHERE genre")
pubic LiveData<List<Movie>> getAllMovies();
}
Repository Class
In the Repository.class, can I pass the genre String selected by the user to the Query this way?
public class MovieRepository {
private MovieDao movieDao;
private LiveData<List<Movie>> allMovies;
public MovieRepository(Application application) {
MovieDatabase database = MovieDatabase.getInstance(application);
movieDao = database.MovieDao();
allMovies = movieDao.getAllMovies
}
public void findMoviesByGenre(String genre) {
movieDao.findMoviesByGenre(genre);
}
}
ViewModel class
I'm not sure if I'm missing something in the findMovieByGenre() method
public class MovieViewModel exteneds AndroidViewModel {
private MovieRepository repository;
private LiveData<List<Movie>> allMovies
// Constructor,
public MovieViewModel(#NonNull Application application) {
super(application);
repository = new MovieRepository(Application)
allMovies = repository.getAllMovies();
}
**public void findMovieByGenre(String genre) {
repository.findMoviesByGenre(genre);
}**
}
Activity
This is the part I'm really struggling with, how does the activity call the ViewModel and pass in the genre string parameter? I've tried the approach below but the observe returns the following error.
Cannot resolve method 'observe(com.example.roomexample.MainActivity, anonymous android.arch.lifecycle.Observer>)'
If I remove the genre string in from of the observe, I get the error below.
findMovieByGenre(String)in MovieViewModel cannot be applied
to ()
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
movieViewModel = ViewModelProviders.of(this). get(MovieViewModel.class);
movieViewModel.findMovieByGenre("comedy").observe(this, new Observer<List<Movie>>() {
#Override
public void onChanged(#Nullable final List<Movie> movies) {
Log.d("Movie", movies.get(num).getTitle());
Log.d("Movie", movies.get(num).getDescription());
Log.d("Movie", movies.get(num).getGenre());
}
});
}
In short I want to match the genre selected by the user and match it to the genre entry in the database and return the matching results.
My code is based on the following tutorials. If you have any additional material that code help me in my quest please pass it along.
Google coding Labs
Coding in Flow
Here is a link to my code as it currently stands.
https://github.com/Shawn-Nichol/RoomExample
If you are using MVVM architecture with LiveData follow this method.
1. Observe the LiveData List in MoviesActivity.java
final LiveData<List<MoviesData>> viewModelData = moviesViewModel.getMoviesByGenre("comedy");
viewModelData.observe(this, new Observer<List<MoviesData>>() {
#Override
public void onChanged(List<MoviesData> moviesData) {
//Handle the Movies List here.
}
});
2. In MoviesViewModel.java
public LiveData<List<NotificationData>> getMoviesByGenre(String genere) {
MoviesRepository mRepository = new MoviesRepository(application);
LiveData<List<MoviesData>> mMoviesData = mRepository.getMoviesByGenre(genere);
return mMoviesData;
}
3. MoviesRepository.java
private MoviesDao mMoviesDao;
//Initialize.
AppDatabase db = AppDatabase.getAppDatabase(application);
mMoviesDao = db.moviesDao();
public LiveData<List<MoviesData>> getMoviesByGenre(String genere) {
mMovies = mMoviesDao.findMovieByGenre(genere);
return mMovies;
}
3. In MoviesDao
#Query("SELECT * FROM movie_table ORDER BY genre")
public LiveData<List<Movies> findMovieByGenre(String genre);
So you can Observe query result in your Activity class' Observe method.
To access your app's data using the Room persistence library, you work with data access objects, or DAOs. You may have to use DAO in android room.
By accessing a database using a DAO class instead of query builders or direct queries, you can separate different components of your database architecture
#Dao
public interface MyDao {
#Query("SELECT * FROM movie_table ORDER BY genre")
public ListMovies[] findMovieByGenre(String Genre);
}
I would like to ask if is possible to have multiple database under one project, with Room Persistence Library? Changing dynamic the selection of the database.
Thanks
It is possible.
Let's assume you have two sets of entities and two sets of DAOs. You can obtain access to two databases by:
creating two classes that extends RoomDatabase:
AppDatabase 1:
#Database(entities = {/*... the first set of entities ...*/}, version = 1)
public abstract class AppDatabase1 extends RoomDatabase {
// the first set of DAOs
}
AppDatabase2:
#Database(entities = {/*... the second set of entities ...*/}, version = 1)
public abstract class AppDatabase2 extends RoomDatabase {
// the second set of DAOs
}
instantiating the two databases:
Note that you'll use two different file names.
AppDatabase db1 = Room.databaseBuilder(getApplicationContext(), AppDatabase1.class, "database1.db").build();
AppDatabase db2 = Room.databaseBuilder(getApplicationContext(), AppDatabase2.class, "database2.db").build();
In this case, you can use both databases, but you won't be able to create queries between them. If you need to attach the two databases, then you should take a look at the link #Anees provided
You can reuse the entities and DAO if databases have the same schema and dynamically switch between them (helpful if you want to have a different database file for each user).
Entity class
#Entity
public class User {
#PrimaryKey
#NonNull
public String uid;
#ColumnInfo(name = "first_name")
public String firstName;
#ColumnInfo(name = "last_name")
public String lastName;
}
DAO class
#Dao
public interface UserDao {
#Query("SELECT * FROM user")
List<User> getAll();
#Query("SELECT * FROM user WHERE uid IN (:userIds)")
List<User> loadAllByIds(int[] userIds);
#Query("SELECT * FROM user WHERE first_name LIKE :first AND " +
"last_name LIKE :last LIMIT 1")
User findByName(String first, String last);
#Insert
void insertAll(User... users);
#Delete
void delete(User user);
}
Database class
#Database(entities = {User.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
public abstract UserDao userDao();
}
DatabaseClient class
public class DatabaseClient {
private Context mCtx;
private AppDatabase appDatabase;
private static String databaseName;
private static DatabaseClient mInstance;
private DatabaseClient(Context mCtx, String dbName) {
this.mCtx = mCtx;
if(databaseName == null || !databaseName.equalsIgnoreCase(dbName)) {
databaseName = dbName;
}
appDatabase = Room.databaseBuilder(mCtx, AppDatabase.class, databaseName).build();
}
public String getDatabaseName() {
return databaseName;
}
public static synchronized DatabaseClient getInstance(Context mCtx, String dbName) {
if (mInstance == null || databaseName == null || !databaseName.equalsIgnoreCase(dbName)) {
mInstance = new DatabaseClient(mCtx, dbName);
}
return mInstance;
}
public AppDatabase getAppDatabase() {
return appDatabase;
}
}
Now you can query based on a particular database by passing its name in the parameter in my case here let's say myDb
List<User> users = DatabaseClient.getInstance(getApplicationContext(), myDb).getAppDatabase().userDao().getAll()
Remember whenever you perform the first call with a database name, it creates the database file. If a new user arrives and calls to insert its info, it automatically creates a new database file and inserts the info data into it.
Just solved it with koin. I was creating an instant message app, and mutiple account login was required. After user1 logon my app, the databse name with im_id could be got, then by inject, I created the database with the id. Then user1 one logout , I just unload the datasource module and jump to the login activity. User2 then login, I reload the datasource module and created database for user2 with his im_id. Code as follows:
val dataSourceModule = module{
single {
Room.databaseBuilder(androidApplication(), AppDataBase::class.java, get<GsSelectedAndImTokenPersistence>().gsImToken?.gsImId ?: "im_database" )
.build()
}
single { get<AppDataBase>().gsInfoDao() }
single { get<AppDataBase>().gsGameInfoDao() }
single { get<AppDataBase>().gameClientDao() }
single { SharedPreferencesDataSourceImpl(androidContext()) } binds (
arrayOf(
ImDeviceIdPersistence::class,
GsSelectedAndImTokenPersistence::class
))
}
fun unLoadDataSourceModule() {
unloadKoinModules(dataSourceModule)
}
fun reLoadDataSourceModule() {
loadKoinModules(dataSourceModule)
}
The interesting is, even if
get().gsImToken?.gsImId
is null, it won't create the default database with name "im_database" by using koin inject.
And This is where I create the database by inject ,after I got the im_id from server
viewModel.gsImToken.observe(provideLifecycleOwner(), {
ELogger.d("database initial","init database===")
// Incase of the datasource module is not loaded by now
KoinInitializer.reLoadDataSourceModule()
val gs: AppDataBase by inject()
gs.gsGameInfoDao().run {
viewModel.initDao(this)
}
})
And the logout place:
class SettingViewModel(
...,
val db: AppDataBase
): ViewModel() {
...
fun onLogout(){
...
db.close()
KoinInitializer.unLoadDataSourceModule()
...
}
}
I've added one to many relationship in Room using Relation.
I referred to this post to write the following code for relation in Room.
The post tells how to read the values from the database but storing the entities into the database resulted in userId to be empty which means there is no relation between the 2 tables.
I'm not sure what is the ideal way to insert a User and List of Pet into the database while having userId value.
1) User Entity:
#Entity
public class User {
#PrimaryKey
public int id; // User id
}
2) Pet Entity:
#Entity
public class Pet {
#PrimaryKey
public int id; // Pet id
public int userId; // User id
public String name;
}
3) UserWithPets POJO:
// Note: No annotation required at this class definition.
public class UserWithPets {
#Embedded
public User user;
#Relation(parentColumn = "id", entityColumn = "userId", entity = Pet.class)
public List<Pet> pets;
}
Now to fetch the records from DB we use the following DAO:
#Dao
public interface UserDao {
#Insert
fun insertUser(user: User)
#Query("SELECT * FROM User")
public List<UserWithPets> loadUsersWithPets();
}
EDIT
I have created this issue https://issuetracker.google.com/issues/62848977 on the issue tracker. Hopefully they will do something regarding it.
You can do this by changing your Dao from an interface to an abstract class.
#Dao
public abstract class UserDao {
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
_insertAll(pets);
}
#Insert
abstract void _insertAll(List<Pet> pets); //this could go in a PetDao instead...
#Insert
public abstract void insertUser(User user);
#Query("SELECT * FROM User")
abstract List<UserWithPets> loadUsersWithPets();
}
You can also go further by having a User object have an #Ignored List<Pet> pets
#Entity
public class User {
#PrimaryKey
public int id; // User id
#Ignored
public List<Pet> pets
}
and then the Dao can map UserWithPets to User:
public List<User> getUsers() {
List<UserWithPets> usersWithPets = loadUserWithPets();
List<User> users = new ArrayList<User>(usersWithPets.size())
for(UserWithPets userWithPets: usersWithPets) {
userWithPets.user.pets = userWithPets.pets;
users.add(userWithPets.user);
}
return users;
}
This leaves you with the full Dao:
#Dao
public abstract class UserDao {
public void insertAll(List<User> users) {
for(User user:users) {
if(user.pets != null) {
insertPetsForUser(user, user.pets);
}
}
_insertAll(users);
}
private void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
_insertAll(pets);
}
public List<User> getUsersWithPetsEagerlyLoaded() {
List<UserWithPets> usersWithPets = _loadUsersWithPets();
List<User> users = new ArrayList<User>(usersWithPets.size())
for(UserWithPets userWithPets: usersWithPets) {
userWithPets.user.pets = userWithPets.pets;
users.add(userWithPets.user);
}
return users;
}
//package private methods so that wrapper methods are used, Room allows for this, but not private methods, hence the underscores to put people off using them :)
#Insert
abstract void _insertAll(List<Pet> pets);
#Insert
abstract void _insertAll(List<User> users);
#Query("SELECT * FROM User")
abstract List<UserWithPets> _loadUsersWithPets();
}
You may want to have the insertAll(List<Pet>) and insertPetsForUser(User, List<Pet>) methods in a PetDAO instead... how you partition your DAOs is up to you! :)
Anyway, it's just another option. Wrapping your DAOs in DataSource objects also works.
There is no native solution till any update in Room Library but you can do this by a trick. Find below mentioned.
Just Create a User with Pets (Ignore pets). Add getter and setter. Notice that we have to set our Id's manually later and can't use autogenerate.
#Entity
public class User {
#PrimaryKey
public int id;
#Ignore
private List<Pet> petList;
}
Create a Pet.
#Entity
public class Pet
{
#PrimaryKey
public int id;
public int userId;
public String name;
}
The UserDao should be an abstract class instead of an Interface. Then finally in your UserDao.
#Insert
public abstract void insertUser(User user);
#Insert
public abstract void insertPetList(List<Pet> pets);
#Query("SELECT * FROM User WHERE id =:id")
public abstract User getUser(int id);
#Query("SELECT * FROM Pet WHERE userId =:userId")
public abstract List<Pet> getPetList(int userId);
public void insertUserWithPet(User user) {
List<Pet> pets = user.getPetList();
for (int i = 0; i < pets.size(); i++) {
pets.get(i).setUserId(user.getId());
}
insertPetList(pets);
insertUser(user);
}
public User getUserWithPets(int id) {
User user = getUser(id);
List<Pet> pets = getPetList(id);
user.setPetList(pets);
return user;
}
Your problem can be solved by this without creating UserWithPets POJO.
As Room does not manage the Relations of the entities, you have to set the userId on each pet yourself and save them. As long as there are not too many pets at once, I'd use an insertAll method to keep it short.
#Dao
public interface PetDao {
#Insert
void insertAll(List<Pet> pets);
}
I don't think there's any better way at the moment.
To make the handling easier, I'd use an abstraction in the layer above the DAOs:
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
petDao.insertAll(pets);
}
Currently there is no native solution to this problem. I have created this https://issuetracker.google.com/issues/62848977 on Google's issue tracker and the Architecture Components Team said they will adding a native solution in or after v1.0 of Room library.
Temporary Workaround:
Meanwhile you can use the solution mentioned by tknell.
public void insertPetsForUser(User user, List<Pet> pets){
for(Pet pet : pets){
pet.setUserId(user.getId());
}
petDao.insertAll(pets);
}
I managed to insert it properly with a relatively simple workaround. Here are my entities:
#Entity
public class Recipe {
#PrimaryKey(autoGenerate = true)
public long id;
public String name;
public String description;
public String imageUrl;
public int addedOn;
}
#Entity
public class Ingredient {
#PrimaryKey(autoGenerate = true)
public long id;
public long recipeId;
public String name;
public String quantity;
}
public class RecipeWithIngredients {
#Embedded
public Recipe recipe;
#Relation(parentColumn = "id",entityColumn = "recipeId",entity = Ingredient.class)
public List<Ingredient> ingredients;
I am using autoGenerate for auto-increment value(long is used with a purpoes).
Here is my solution:
#Dao
public abstract class RecipeDao {
public void insert(RecipeWithIngredients recipeWithIngredients){
long id=insertRecipe(recipeWithIngredients.getRecipe());
recipeWithIngredients.getIngredients().forEach(i->i.setRecipeId(id));
insertAll(recipeWithIngredients.getIngredients());
}
public void delete(RecipeWithIngredients recipeWithIngredients){
delete(recipeWithIngredients.getRecipe(),recipeWithIngredients.getIngredients());
}
#Insert
abstract void insertAll(List<Ingredient> ingredients);
#Insert
abstract long insertRecipe(Recipe recipe); //return type is the key here.
#Transaction
#Delete
abstract void delete(Recipe recipe,List<Ingredient> ingredients);
#Transaction
#Query("SELECT * FROM Recipe")
public abstract List<RecipeWithIngredients> loadAll();
}
I had problem linking the entities, auto generate produced "recipeId=0" all the time. Inserting the recipe entity firstly fixed it for me.
Now at v2.1.0 Room seems to be not suitable for models with nested relations. It needed lots of boilerplate code to maintain them. E.g. manual insert of lists, creating and mapping local IDs.
This relations-mapping operations are done out of box by Requery https://github.com/requery/requery Additionaly it does not have issues with inserting Enums and have some converters for other complex types like URI.