You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 04:23:20