Swift Realm中DBOfflineOrder无主键无法更新问题咨询
解决Realm中
DBOfflineOrder无主键导致更新报错的问题 这个问题我之前也碰到过,Realm的报错原因很明确——当你尝试更新对象时,Realm需要通过主键来定位数据库里已有的记录,而你的DBOfflineOrder没有定义主键,自然没法完成更新操作。给你几个实用的解决办法,按推荐程度排序:
方法一:给实体添加主键(最推荐)
这是Realm设计的标准用法,后续的更新、查找操作都会更高效便捷。你可以选择新增一个唯一标识字段,或者直接用现有业务上唯一的字段(比如你的number字段,看起来是订单号,应该是唯一的)作为主键。
代码示例(新增UUID主键):
class DBOfflineOrder: Object { @objc dynamic var id: String = UUID().uuidString // 自动生成唯一ID @objc dynamic var date: String = "" @objc dynamic var orderDescription: String = "" @objc dynamic var email: String = "" @objc dynamic var phone: String = "" @objc dynamic var login: String = "" @objc dynamic var number: String = "" @objc dynamic var amount: Double = 0.0 @objc dynamic var discount: Double = 0.0 let products = List<ProductOffline>() // 声明主键字段 override static func primaryKey() -> String? { return "id" } }
如果你想用现有number作为主键(更贴合业务):
只需要把primaryKey()的返回值改成"number"即可,前提是确保number字段在所有订单中都是唯一的:
override static func primaryKey() -> String? { return "number" }
注意:添加主键后需要做数据迁移
如果你的App已经有用户在使用(即存在旧的Realm数据库文件),修改schema后必须做迁移,否则会报错。迁移代码示例:
// 配置Realm迁移 let config = Realm.Configuration( schemaVersion: 1, // 版本号比之前加1(原来默认是0) migrationBlock: { migration, oldSchemaVersion in if oldSchemaVersion < 1 { // 给旧数据添加主键值,这里用number作为id示例 migration.enumerateObjects(ofType: DBOfflineOrder.className()) { oldObject, newObject in newObject!["id"] = oldObject!["number"] as! String // 如果你是把number设为主键,不需要这一步,Realm会自动处理 } } } ) // 设置为默认配置 Realm.Configuration.defaultConfiguration = config // 初始化Realm let realm = try! Realm()
方法二:无主键情况下,改用"查询-修改"模式更新对象
如果因为某些限制不能添加主键,你可以先通过唯一字段(比如number)查询现有订单,找到后在事务中修改属性,找不到再创建新对象:
let realm = try! Realm() let targetOrderNumber = "你的订单号" try! realm.write { // 查询是否存在该订单 if let existingOrder = realm.objects(DBOfflineOrder.self).filter("number == %@", targetOrderNumber).first { // 修改现有订单的属性 existingOrder.date = "新日期" existingOrder.amount = 199.99 // 其他属性同理修改,products列表也可以在事务中操作(比如append/remove) } else { // 创建新订单并添加到数据库 let newOrder = DBOfflineOrder() newOrder.number = targetOrderNumber newOrder.date = "当前日期" // 其他属性赋值... realm.add(newOrder) } }
这种方法的缺点是需要额外的查询操作,效率不如主键更新高,而且依赖业务上的唯一字段来定位对象。
方法三:如果只是误触更新操作,改为仅新增对象
如果你本来就不需要更新,只是想添加新的订单对象,那直接去掉create方法中的update参数即可:
原来的错误调用(带update):
// 会报错的写法 realm.create(DBOfflineOrder.self, value: orderData, update: .all)
改成仅新增:
// 正确的新增写法 realm.create(DBOfflineOrder.self, value: orderData) // 或者直接创建对象后添加 let newOrder = DBOfflineOrder() // 属性赋值... realm.add(newOrder)
内容的提问来源于stack exchange,提问作者Evgeniy Kleban
相关产品推荐
相关产品推荐

