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主键。
解决方案
- 在ProductDao中添加查询方法:
@Query("SELECT * FROM product WHERE barcode = :barcode") Product getProductByBarcode(String barcode);
- 更新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
相关产品推荐
相关产品推荐

