Room数据库中是否需单独存储Ingredient与Step实体?
Room数据库离线食谱实现疑问
我现在有Recipe、Ingredient、Step三个POJO类,为实现离线浏览食谱功能用了Room数据库,已经写了部分代码,现在有几个疑问:
通过Converters类将
List<Step>和List<Ingredient>以字符串形式保存后,我是否还需要为Step.class和Ingredient.class分别创建数据库表?是否需要为这两个类添加@Entity注解?是否需要创建StepDatabase和IngredientDatabase?这些操作是实现离线访问食谱的必要步骤吗?
已实现的代码:
Recipe.class
@Entity(tableName = "recipe") public class Recipe implements Parcelable { @PrimaryKey(autoGenerate = false) @SerializedName("id") public int recipeId; @ColumnInfo(name = "recipe_name") public String name; @TypeConverters(Converters.class) public List<Ingredient> ingredients = null; @TypeConverters(Converters.class) public List<Step> steps = null; @ColumnInfo(name = "recipe_servings") public int servings; @Ignore public String image; public Recipe(int recipeId, String name, List<Ingredient> ingredients, List<Step> steps, int servings, String image) { this.recipeId = recipeId; this.name = name; this.ingredients = ingredients; this.steps = steps; this.servings = servings; this.image = image; } ... //getters and setters ... }
Converters.class
public class Converters { static Gson gson = new Gson(); @TypeConverter public static List<Ingredient> stringToIngredientList(String data) { if (data == null) { return Collections.emptyList(); } Type listType = new TypeToken<List<Ingredient>>() {}.getType(); return gson.fromJson(data, listType); } @TypeConverter public static String ingredientListToString(List<Ingredient> ingredients) { return gson.toJson(ingredients); } @TypeConverter public static List<Step> stringToStepList(String data) { if (data == null) { return Collections.emptyList(); } Type listType = new TypeToken<List<Step>>() {}.getType(); return gson.fromJson(data, listType); } @TypeConverter public static String stepListToString(List<Step> steps) { return gson.toJson(steps); } }
RecipeDatabase.class
@Database(entities = {Recipe.class}, version = 1) abstract class RecipeDatabase extends RoomDatabase { private static RecipeDatabase INSTANCE; public abstract RecipeDao recipeDao(); public static RecipeDatabase getRecipeDatabase(Context context) { if (INSTANCE == null) { INSTANCE = Room.databaseBuilder(context.getApplicationContext(), RecipeDatabase.class, "recipe-database") // allow queries on the main thread. // Don't do this on a real app! See PersistenceBasicSample for an example. .allowMainThreadQueries() .build(); } return INSTANCE; } public static void destroyInstance() { INSTANCE = null; } }
RecipeDao.class
@Dao public interface RecipeDao { @Query("SELECT * FROM recipe") List<Recipe> getAll(); @Query("SELECT * FROM recipe where recipe_name LIKE :name") Recipe findByName(String name); @Query("SELECT COUNT(*) from recipe") int countRecipes(); @Update void update(Recipe... recipes); @Insert void insertAll(Recipe... recipes); @Delete void delete(Recipe recipe); }
问题解答
直接给你明确的结论,再解释背后的逻辑:
- 不需要为
Step和Ingredient创建单独的数据库表,也不需要给它们加@Entity注解 - 不需要创建
StepDatabase和IngredientDatabase - 这些操作完全不是实现离线访问食谱的必要步骤
为什么?
你当前用TypeConverter把List<Ingredient>和List<Step>转换成JSON字符串,存储在Recipe表的对应字段里,这种方式属于嵌入式存储——把嵌套的对象/列表直接序列化后存在主表的字段中。对于你的核心需求(离线浏览整个食谱)来说,这种方式完全够用:
- 当你从数据库读取
Recipe时,Room会自动调用Converter把JSON字符串转回List<Ingredient>和List<Step>,你可以直接用这些数据展示完整的食谱内容。 - 这种方式实现简单,不需要处理多表关联(比如外键),适合数据关联性强、不需要单独查询子对象的场景。
什么时候需要单独建表?
如果后续你的需求扩展,比如需要单独查询某个食谱的某一种食材、统计所有食谱里用到的某类步骤,这种扁平化存储的方式就会很麻烦——你必须先读出所有Recipe,再遍历它们的Ingredients/Steps来筛选。这时候才需要给Ingredient和Step加@Entity注解,建立单独的表,并且通过外键关联到Recipe的recipeId,实现多表查询。
但就你当前的“离线浏览食谱”需求而言,现有的实现已经足够,完全不需要额外建表或数据库。
内容的提问来源于stack exchange,提问作者yalematta
相关产品推荐
相关产品推荐

