iOS Core Data问题:重复ID对象保存未覆盖旧对象
Core Data 保存重复ID对象问题
我是Core Data新手,保存对象时碰到个问题:希望保存相同ID(主键)的对象时,不会生成新条目,就像Android Room里的OnConflictStrategy.REPLACE那样(二者都基于SQLite)。我已经用了合并策略但没效果,相关代码和数据模型如下:
保存方法代码
static func addPost(post:Post){ guard let context = context else { print("post add error with context core data") return } context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy let p = PostDao(context: context) p.id = post.id p.username = post.username p.title = post.title p.photo = post.photo p.location = post.location p.contactPhone = post.contactPhone p.isPostDeleted = post.isPostDeleted! p.postDescription = post.postDescription p.lastUpdated = post.lastUpdated p.contactEmail = post.contactEmail do{ try context.save() }catch let error as NSError{ print("post add error core data\(error) \(error.userInfo)") } }
Post 实体类代码
class Post{ public var id: String? = "" public var title: String? = "" public var username: String? = "" public var postDescription: String? = "" public var photo: String? = "" public var location: String? = "" public var contactPhone: String? = "" public var contactEmail: String? = "" public var isPostDeleted: Bool? = false public var lastUpdated:Int64 = 0 init(){} init(post:PostDao){ id = post.id title = post.title postDescription = post.postDescription username = post.username photo = post.photo isPostDeleted = post.isPostDeleted lastUpdated = post.lastUpdated location = post.location contactPhone = post.contactPhone contactEmail = post.contactEmail } }
PostDao Core Data 扩展代码
extension PostDao { @nonobjc public class func fetchRequest() -> NSFetchRequest<PostDao> { return NSFetchRequest<PostDao>(entityName: "PostDao") } @NSManaged public var id: String? @NSManaged public var title: String? @NSManaged public var username: String? @NSManaged public var photo: String? @NSManaged public var postDescription: String? @NSManaged public var location: String? @NSManaged public var contactPhone: String? @NSManaged public var contactEmail: String? @NSManaged public var isPostDeleted: Bool @NSManaged public var lastUpdated: Int64 } extension PostDao : Identifiable { }
数据模型

解决方法
你的问题核心在于每次调用addPost都直接创建了新的PostDao对象,没有先检查数据库中是否存在相同ID的条目,合并策略只有在上下文出现对象冲突时才会生效,而你当前的逻辑根本没触发冲突。
正确的实现步骤应该是:
- 先根据传入
Post的ID查询数据库中是否已有对应的PostDao对象 - 如果存在,就更新该对象的属性;如果不存在,再创建新对象
- 合并策略可提前设置到上下文,无需每次保存时重复设置
修改后的addPost方法示例:
static func addPost(post: Post) { guard let context = context else { print("post add error with context core data") return } // 建议将合并策略放到上下文初始化代码中,无需每次调用都设置 context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy // 1. 根据ID查询已有对象 let fetchRequest: NSFetchRequest<PostDao> = PostDao.fetchRequest() fetchRequest.predicate = NSPredicate(format: "id == %@", post.id ?? "") do { let existingPosts = try context.fetch(fetchRequest) let postDao: PostDao if let existingPost = existingPosts.first { // 2. 存在则更新属性 postDao = existingPost postDao.username = post.username postDao.title = post.title postDao.photo = post.photo postDao.location = post.location postDao.contactPhone = post.contactPhone postDao.isPostDeleted = post.isPostDeleted ?? false postDao.postDescription = post.postDescription postDao.lastUpdated = post.lastUpdated postDao.contactEmail = post.contactEmail } else { // 3. 不存在则创建新对象 postDao = PostDao(context: context) postDao.id = post.id postDao.username = post.username postDao.title = post.title postDao.photo = post.photo postDao.location = post.location postDao.contactPhone = post.contactPhone postDao.isPostDeleted = post.isPostDeleted ?? false postDao.postDescription = post.postDescription postDao.lastUpdated = post.lastUpdated postDao.contactEmail = post.contactEmail } // 保存上下文 try context.save() } catch let error as NSError { print("post add error core data \(error) \(error.userInfo)") } }
另外还有两个优化建议:
- 给
id字段添加唯一约束:在Core Data模型编辑器中,选中PostDao实体的id属性,在右侧检查器的「Constraints」里添加id UNIQUE约束,从数据库层面阻止重复ID插入,配合合并策略更可靠 - 替换强制解包
post.isPostDeleted!:改用post.isPostDeleted ?? false的可选绑定方式,避免因nil值导致崩溃
内容的提问来源于stack exchange,提问作者Shimon Cohen
相关产品推荐
相关产品推荐

