Room数据库@Insert仅插入单条记录:Gson解析致gid全为0
解决Room插入多条记录仅保留1条的Gson解析问题
嘿,这个坑我之前也踩过!核心问题就是Gson解析时没给gid主键赋值,导致所有对象的gid都是默认值0,再加上你用了OnConflictStrategy.REPLACE策略,后面插入的记录会不断覆盖前面的,最后自然只剩一条。下面给你几个靠谱的解决方案:
方案1:让Room自动生成主键(最推荐)
这是最简单直接的方式,修改Genre实体类的主键注解,加上autoGenerate = true,Room会自动为每条插入的记录分配唯一的自增主键,完全不用管Gson解析的问题:
@Entity(indices = {@Index(value = {"id", "name"}, unique = true)}) public class Genre { @PrimaryKey(autoGenerate = true) // 新增autoGenerate=true,让Room自动生成主键 private int gid; @NonNull private int id; private String name; // 以下getter、setter保持不变 public int getGid() { return gid; } public void setGid(int gid) { this.gid = gid; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
修改后调用insertAll()时,Room会自动给每个Genre对象的gid分配唯一的递增数值,再也不会出现主键冲突覆盖的情况。
方案2:手动为每个Genre分配唯一gid(适合自定义主键规则的场景)
如果业务原因必须自己管理gid,可以在Gson解析后手动给每个对象设置唯一值,比如用自增数字:
@Override public void onSuccess(JSONArray jsonArray) { Gson gson = new Gson(); Genre[] genres = gson.fromJson(jsonArray.toString(), Genre[].class); // 手动为每个Genre分配唯一gid for (int i = 0; i < genres.length; i++) { genres[i].setGid(i + 1); // 简单自增,也可以用UUID或其他可靠生成规则 } // 插入数据库 AppDatabase db = AppDatabase.getAppDatabase(context); GenreRepository genreRepository = new GenreRepository(db.genreDao()); genreRepository.insertAll(genres); }
不过这种方式不如方案1省心,毕竟Room的自动主键生成是经过优化的,能避免重复问题。
方案3:调整Gson解析规则(不推荐,性价比低)
你也可以通过Gson的自定义反序列化规则,让解析时自动生成gid,但需要额外写代码,可靠性也不如Room自增:
Gson gson = new GsonBuilder() .registerTypeAdapter(Genre.class, new JsonDeserializer<Genre>() { @Override public Genre deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { Genre genre = context.deserialize(json, Genre.class); // 用时间戳作为临时主键,不保证绝对唯一 genre.setGid((int) System.currentTimeMillis()); return genre; } }) .create(); Genre[] genres = gson.fromJson(jsonArray.toString(), Genre[].class);
这种方式有重复风险,所以优先选方案1。
额外提醒:检查业务主键合理性
你给id和name加了联合唯一索引,如果后端返回的id是业务唯一标识,其实可以直接把id设为主键(去掉gid),更贴合业务逻辑:
@Entity(indices = {@Index(value = {"name"}, unique = true)}) public class Genre { @PrimaryKey @NonNull private int id; private String name; // getter、setter... }
这样Gson解析时会直接用后端返回的id作为主键,也不会出现覆盖问题,具体看你的业务需求。
内容的提问来源于stack exchange,提问作者Coova
相关产品推荐
相关产品推荐

