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

Core Data:User数据已保存但无法获取的问题求助

Core Data关联数据读取异常问题排查

问题概述

使用Core Data管理数据:UserList实体存储登录用户的identifier,与Users、UserLinks、UserAllowedSellRoles、UserAllowedBuyRoles为一对多关系。调用saveUsers方法保存数据后,SQLite数据库确认Users数据已写入,但通过getUsersInfo读取UserList关联数据时,仅sellRoles、userLinks、buyRoles有数据,Users数据为空。已验证实体关系配置正确,近期新增Users实体的id约束并更新了Core Data模型版本,怀疑问题与数据迁移相关。

相关代码

保存方法

static func saveUsers(_ id: String, userDetails: [JSON?],userLinks: [JSON?], userBuyRoles: [JSON?], userSellRoles: [JSON?],completion:@escaping ( Bool) -> ()) {
    let context = CoreDataStack.shared.persistentContainer.viewContext
    context.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "UserList")
    request.returnsObjectsAsFaults = false
    request.predicate = NSPredicate(format: "identifier == '\(id)'")
    
    do {
        var usersArray = [Users]()
        
        for obj in userDetails {
            let entityUsers = NSEntityDescription.entity(forEntityName: "Users", in: context)
            let usersObj = NSManagedObject(entity: entityUsers!, insertInto: context) as! Users
            usersObj.id = Int16(obj?["id"].intValue ?? 0)
            usersObj.firstName = obj?["first_name"].stringValue
            usersObj.lastName = obj?["last_name"].stringValue
            //other properties related to user
            usersArray.append(usersObj)
        }
        
        var userLinksArray = [UserLinks]()
        
        for objUserLinks in userLinks {
            let entityUserLinks = NSEntityDescription.entity(forEntityName: "UserLinks", in: context)
            let userLinksObj = NSManagedObject(entity: entityUserLinks!, insertInto: context) as! UserLinks
            userLinksObj.url = objUserLinks?["url"].stringValue
            //other properties related to user links
            
            userLinksArray.append(userLinksObj)
        }
        
        var userAllowedSellRolesArray = [UserAllowedSellRoles]()
        
        for objSellRoles in userSellRoles {
            let entityUsers = NSEntityDescription.entity(forEntityName: "UserAllowedSellRoles", in: context)
            let userAllowedSellRolesObj = NSManagedObject(entity: entityUsers!, insertInto: context) as! UserAllowedSellRoles
            //properties related to user sell roles
            
            userAllowedSellRolesArray.append(userAllowedSellRolesObj)
            
        }
        
        var userAllowedBuyRolesArray = [UserAllowedBuyRoles]()
        
        for objBuyRoles in userBuyRoles {
            let entityUserAllowedBuyRoles = NSEntityDescription.entity(forEntityName: "UserAllowedBuyRoles", in: context)
            let userAllowedBuyRolesObj = NSManagedObject(entity: entityUserAllowedBuyRoles!, insertInto: context) as! UserAllowedBuyRoles
            //properties related to buy roles
        }
        
        let results = try context.fetch(request) as? [NSManagedObject]
        if results?.count ?? 0 > 0 {
            let userListObj = results?.first  as! UserList
            userListObj.identifier = id
            userListObj.user = NSSet(array: usersArray)
            userListObj.userLinks = NSSet(array:userLinksArray)
            userListObj.buyRoles = NSSet(array:userAllowedBuyRolesArray)
            userListObj.sellRoles = NSSet(array:userAllowedSellRolesArray)
            
            try context.save()
            print("Stored Data Successfully")
            completion(true)
            
        }else {
            let entity = NSEntityDescription.entity(forEntityName: "UserList", in: context)
            let userListObj = NSManagedObject(entity: entity!, insertInto: context) as! UserList
            userListObj.identifier = id
            userListObj.user = NSSet(array: usersArray)
            
            userListObj.userLinks = NSSet(array:userLinksArray)
            userListObj.buyRoles = NSSet(array:userAllowedBuyRolesArray)
            userListObj.sellRoles = NSSet(array:userAllowedSellRolesArray)
            try context.save()
            print("Stored Data Successfully")
            completion(true)
        }
    } catch {
        print("Fetch Failed: \(error)")
        completion(false)
    }
}

获取方法

static func getUsersInfo(_ completion:@escaping (NSArray,NSArray,NSArray ) -> ()) {
    let context = CoreDataStack.shared.persistentContainer.viewContext
    print("Fetching Data")
    let request = NSFetchRequest<NSFetchRequestResult>(entityName: "UserList")
    request.returnsObjectsAsFaults = false
    do {
        guard let results = try context.fetch(request) as? [NSManagedObject] else { return}
        
        for obj in results {
          let userObject = obj as? UserList
            let users =  (userObject!.user! as NSSet).allObjects as NSArray
            let buyRoles = (userObject!.buyRoles! as NSSet).allObjects as NSArray
            let sellRoles = (userObject!.sellRoles! as NSSet).allObjects as NSArray
            
            print("users \(users)")
            print("buyRoles \(buyRoles)")
            print("sellRoles \(sellRoles)")
            completion(users,buyRoles,sellRoles)
        }
       
    } catch {
        print("Fetch Failed: \(error)")
    }
}

排查方向与解决方案

1. 模型迁移导致关系映射失效

新增Users.id约束并更新模型版本时,可能破坏了UserList与Users的关联映射。

  • 检查模型版本中UserList与Users的关系配置:确认反向关系(Inverse)已正确设置,删除规则(Delete Rule)符合业务逻辑。
  • 若使用手动迁移,重新生成迁移映射文件;若使用自动迁移,清理App缓存后重新测试,避免旧模型数据干扰。

2. 重复Users对象被合并导致关联丢失

由于新增了Users.id唯一约束,创建重复id的Users对象时,Core Data的合并策略可能丢弃新对象,但未正确维护UserList的关联关系。

  • 修改saveUsers中创建Users对象的逻辑,先查询是否已存在相同id的对象:
    for obj in userDetails {
        let userId = obj?["id"].intValue ?? 0
        let userRequest = NSFetchRequest<Users>(entityName: "Users")
        userRequest.predicate = NSPredicate(format: "id == %d", userId)
        
        if let existingUser = try? context.fetch(userRequest).first {
            usersArray.append(existingUser)
        } else {
            let usersObj = Users(context: context)
            usersObj.id = Int16(userId)
            usersObj.firstName = obj?["first_name"].stringValue
            usersObj.lastName = obj?["last_name"].stringValue
            // 其他属性赋值
            usersArray.append(usersObj)
        }
    }
    
  • 确保Users实体已配置指向UserList的反向关系,Core Data依赖双向关系维护关联完整性。

3. 延迟加载导致读取时数据未加载

Core Data的延迟加载(Faulting)机制可能导致user关联数据未被实际加载,打印时仅显示Fault对象。

  • 在getUsersInfo的查询请求中添加预加载配置:
    request.relationshipKeyPathsForPrefetching = ["user", "buyRoles", "sellRoles"]
    
  • 或在读取时强制触发数据加载:
    let users = (userObject!.user! as NSSet).allObjects as [Users]
    users.forEach { _ = $0.firstName } // 访问任意属性触发加载
    completion(users as NSArray, buyRoles, sellRoles)
    

4. 合并策略覆盖原有关联

当前设置的NSMergeByPropertyObjectTrumpMergePolicy在更新UserList时,可能直接覆盖原有user关联,导致旧数据丢失。

  • 更新已有UserList对象时,合并新数据与原有关联,而非直接替换:
    if results?.count ?? 0 > 0 {
        let userListObj = results?.first as! UserList
        userListObj.identifier = id
        
        // 合并新Users数组与原有关联
        let existingUsers = userListObj.user?.mutableCopy() as! NSMutableSet
        existingUsers.addObjects(from: usersArray)
        userListObj.user = existingUsers.copy() as? NSSet
        
        // 其他关联设置
        userListObj.userLinks = NSSet(array:userLinksArray)
        userListObj.buyRoles = NSSet(array:userAllowedBuyRolesArray)
        userListObj.sellRoles = NSSet(array:userAllowedSellRolesArray)
        
        try context.save()
        completion(true)
    }
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 01:17:03