I'm trying to build a database that has two tables with a one to many relationship. (one recipe belongs to many ingredients)
It looks like I have setup everything correctly I think but now when I build the database I want to pre-populate is with some recipes and the ingredients that belong to the recipe. But I don't know how to implement this in the database builder.
Here is my recipe table:
@Entity(tableName = "recipe_table") //Represents the table in SQLite database
public class Recipe {
@PrimaryKey(autoGenerate = true)
private int id; //Holds the id of the recipe
private String title; //Holds the name of the recipe
@Ignore
private List<Ingredient> ingredientsList;
//Generate constructor to create objects later
public Recipe(String title, List<Ingredient> ingredientsList) {
this.title = title;
this.ingredientsList = ingredientsList;
}
//Generate getters to persist values to the database
public int getId() {
return id;
}
//Generate setter so that room can recreate later
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public List<Ingredient> getIngredientsList() {
return ingredientsList;
}
public void setIngredientsList(List<Ingredient> ingredientsList) {
this.ingredientsList = ingredientsList;
}
}
A Ingredient table:
package com.example.kookrecepten;
import androidx.room.Entity;
import androidx.room.ForeignKey;
import androidx.room.Ignore;
import androidx.room.PrimaryKey;
import java.util.List;
import static androidx.room.ForeignKey.CASCADE;
@Entity(foreignKeys = @ForeignKey(entity = Recipe.class, parentColumns = "id", childColumns = "recipeId", onDelete = CASCADE))
public class Ingredient {
@PrimaryKey
private int id;
private int recipeId;
private String title; //Name of the ingredient
@Ignore
private List<Ingredient> ingredientsList;
public Ingredient(String title, int recipeId) {
this.title = title;
this.recipeId = recipeId;
}
public void setId(int id) {
this.id = id;
}
public void setRecipeId(int recipeId) {
this.recipeId = recipeId;
}
public int getId() {
return id;
}
public int getRecipeId() {
return recipeId;
}
public String getTitle() {
return title;
}
}
This is my dao file
@Dao
public abstract class RecipeDao {
//Insert recipe
@Insert
public abstract void insertRecipe(Recipe recipe);
//Insert ingredients list
@Insert
public abstract void insertIngredientList(List<Ingredient> ingredients);
@Query("SELECT * FROM recipe_table WHERE id =:id")
public abstract Recipe getRecipe(int id);
@Query("SELECT * FROM Ingredient WHERE recipeId =:recipeId")
public abstract List<Ingredient> getIngredientList(int recipeId);
public void insertRecipeWithIngredients(Recipe recipe) {
List<Ingredient> ingredients = recipe.getIngredientsList();
for (int i = 0; i < ingredients.size(); i++) {
ingredients.get(i).setRecipeId(recipe.getId());
}
insertIngredientList(ingredients);
insertRecipe(recipe);
}
public Recipe getRecipeWithIngredients(int id) {
Recipe recipe = getRecipe(id);
List<Ingredient> ingredients = getIngredientList(id);
recipe.setIngredientsList(ingredients);
return recipe;
}
}
But my problem is I have no idea how to prepopulate my database.
private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
private RecipeDao recipeDao;
private PopulateDbAsyncTask(RecipeDatabase db) {
recipeDao = db.recipeDao();
}
@Override
protected Void doInBackground(Void... voids) {
recipeDao.insertRecipeWithIngredients(
//insert a recipe and a list of ingredients?
);
return null;
}
}
First of all, I recommend you NOT to you AsyncTask as it's deprecated . hit official documentation for more details.
Secondly you 3 options for prepopulating your database as follow:
1) createFromAssets : in this option, you may create a directory called "databases" under assets folder so your could will be as follow:
.createFromAssets("/databases/YOUR DATABASE FILENAME")
2) createFromFile : This option may work with the file you are assigning its path.
.createFromFile(File("YOUR FILE PATH"))
if you are stuck with these two solutions, you can try the manual solution, we may call it manual solution yeah.. by accessing your database file in assets folder.
private fun copyDBFromStorage(databaseName: String) {
if (checkIfDBExists(this, databaseName)) return
val databaseFile = File(this.getDatabasePath(databaseName).toString())
val sourceLocation = assets.open("Your database file path")
try {
val inputStream = sourceLocation
val os = FileOutputStream(databaseFile)
val buffer = ByteArray(1024 * 32)
var length = inputStream.read(buffer)
while (length > 0) {
os.write(buffer, 0, length)
length = inputStream.read(buffer)
}
os.flush()
os.close()
inputStream.close()
} catch (ex: IOException) {
ex.printStackTrace();
throw RuntimeException("Error copying storage database");
}
}
private fun checkIfDBExists(
context: Context,
databaseName: String
): Boolean {
val dbfile = File(context.getDatabasePath(databaseName).toString())
if (dbfile.exists()) return true
if (!dbfile.parentFile.exists()) {
dbfile.parentFile.mkdirs()
}
return false
}
I hope this would help
Happy coding
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.