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

Android Room中带唯一索引实体的Upsert及关联数据更新

Android Room一对多数据存储问题及解决

问题背景

从API获取的JSON数据格式如下:

"product": {
  "barcode": "2489752310342",
  "productName": "Trench coat",
  "priceList": [
    {
      "price": 345
    },
    {
      "price": 123
    }
  ]
}

需将数据写入Android Room数据库,Product与Price实体为一对多关系,要求拆分存储(禁止用Type Converter将priceList存为字符串)。

实体类定义

Product实体

@Entity(tableName = "product", indices = {@Index(value = {"barcode"},
        unique = true)})
public class Product {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    private int id;

    @ColumnInfo(name = "barcode")
    private String barcode;

    @ColumnInfo(name = "product_name")
    private String productName;

    @ColumnInfo(name = "price_list")
    @Ignore
    private ArrayList<Price> priceList;
}

Price实体

@Entity(tableName = "price",
        foreignKeys = @ForeignKey(
                entity = Product.class,
                parentColumns = "id",
                childColumns = "product_id",
                onDelete = ForeignKey.CASCADE,
                onUpdate = ForeignKey.CASCADE
        ))
public class Price {

    @PrimaryKey(autoGenerate = true)
    @ColumnInfo(name = "id")
    private int id;

    @ColumnInfo(name = "product_id")
    private int productId;

    @ColumnInfo(name = "price")
    private int price;
}

原有实现逻辑

原逻辑为先Upsert Product获取ID,再为Price设置关联ID后写入:

private void upsertProduct(Product product){
    int insertedRowId = (int) productDao.upsertData(product);
    product.setId(insertedRowId);
    addPricesDependOnProductId(product);
}
private void addPricesDependOnProductId(Product product) {
    for (Price price : product.getPriceList()) {
        price.setProductId(product.getId());
        priceDao.upsertPrice(price);
    }
}

遇到的问题

要求删除Price表所有数据后重新插入,但不能改变Product的ID。执行时触发错误:UNIQUE constraint failed: product.barcode (code 2067 SQLITE_CONSTRAINT_UNIQUE),原因是重复插入了已有唯一索引的barcode。期望实现:若Product已存在,复用原有ID关联Price,且不递增Product主键。

解决方案

  1. 在ProductDao中添加查询方法:
@Query("SELECT * FROM product WHERE barcode = :barcode")
Product getProductByBarcode(String barcode);
  1. 更新upsertProduct方法:
private void upsertProduct(Product product){
        String barcode = product.getBarcode();
        new Thread(() -> {
            Product productInDB = productDao.getProductByBarcode(barcode);
            if (productInDB == null) {
                // 数据库中无该barcode的商品则插入并获取ID
                int insertedRowId = (int) productDao.upsertData(product);
                product.setId(insertedRowId);
                addPricesDependOnProductId(product);
            } else {
                // 商品已存在则复用原有ID更新价格列表
                productInDB.setPriceList(product.getPriceList());
                addPricesDependOnProductId(productInDB);
            }
        }).start();
}

内容的提问来源于stack exchange,提问作者oguzata

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 12:27:55