首页 > 解决方案 > 尝试预填充房间数据库

问题描述

我正在尝试构建一个具有两个具有一对多关系的表的数据库。(一个食谱属于多种成分)

看起来我已经正确设置了我认为的所有内容,但是现在当我构建数据库时,我想要预填充一些食谱和属于该食谱的成分。但我不知道如何在数据库构建器中实现这一点。

这是我的食谱表:

@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;
    }
}

成分表:

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;
    }
}

这是我的 dao 文件

@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;
    }
}

但我的问题是我不知道如何预填充我的数据库。

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;
        }
    }

标签: javaandroidinsertandroid-room

解决方案


首先,我建议您不要 AsyncTask 因为它已弃用。点击官方文档了解更多详情。

其次,您有 3 个用于预填充数据库的选项,如下所示:

1) createFromAssets:在此选项中,您可以在 assets 文件夹下创建一个名为“databases”的目录,因此您可以如下所示:

.createFromAssets("/databases/YOUR DATABASE FILENAME")

2) createFromFile:此选项可能适用于您分配其路径的文件。

.createFromFile(File("YOUR FILE PATH"))

如果您对这两种解决方案感到困惑,您可以尝试手动解决方案,我们可以称之为手动解决方案是的!通过访问资产文件夹中的数据库文件。

    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
}

我希望这会有所帮助

快乐编码


推荐阅读