简体   繁体   中英

Try to prepopulate room database

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM