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

单元测试读取数据库时抛出SingleValueContainer错误求助

解决读取数据库时的「decoding a single value container is not supported」错误

问题场景

单元测试中已成功向数据库写入AddressTypeTwo记录,但调用get方法读取时,抛出「decoding a single value container is not supported」错误。相关代码如下:

Codable结构体定义

struct AddressTypeTwo: Codable {
    // MARK: CRUD
    var id: Int?
    var created: Date?
    var createdBy: String?
    var modified: Date?
    var modifiedBy: String?
    var deleted: Date?
    var deletedBy: String?
    
    var name: String?
    var companyId: Int?
    
    // MARK: CodingKeys
    enum CodingKeys: String, CodingKey {
        case id, created, createdBy, modified, modifiedBy
        case deleted, deletedBy
        case name
        case companyId = "company_id"
    }
}

插入函数(运行正常)

func insert(toBeInserted obj: Codable) -> Int {
    if let newId = try? DbSupport.shared.activeDatabase?.run(table.insert(obj)) {
        return Int(newId)
    }
    return -1
}

触发错误的读取函数

func get<T: Codable>(_ includeDeleted: Bool = false) -> [T]? {
    var query = table.filter(tableDeleted == nil)
    if includeDeleted {
        query = table
    }
    
    guard let database = DbSupport.shared.activeDatabase else { return nil }
    
    let addresses: [T?]? = try? database.prepare(query).map { row in
        if let rowData: T = try? row.decode() {
            return rowData
        }
        return nil
    }
    
    return addresses?.compactMap { $0 }
}

问题原因

错误的核心是row.decode()调用未明确指定解码目标类型,导致数据库库的解码逻辑默认尝试将行数据解析为单个值类型(如Int、String),但我们需要解码的是复合结构的AddressTypeTwo,二者不匹配从而触发错误。

解决方案

修改读取函数中的解码逻辑,明确指定要解码的泛型类型T.self:

func get<T: Codable>(_ includeDeleted: Bool = false) -> [T]? {
    var query = table.filter(tableDeleted == nil)
    if includeDeleted {
        query = table
    }
    
    guard let database = DbSupport.shared.activeDatabase else { return nil }
    
    do {
        let addresses: [T] = try database.prepare(query).map { row in
            try row.decode(T.self)
        }
        return addresses
    } catch {
        print("读取解码失败:\(error)")
        return nil
    }
}

额外检查点

  1. Date类型解码匹配:如果数据库中Date字段存储的是时间戳(而非ISO8601字符串),需要配置Decoder的dateDecodingStrategy,确保与存储格式一致。例如:
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .secondsSince1970
// 可根据实际存储格式调整为.millisecondsSince1970或自定义策略
  1. 表字段与CodingKeys匹配:确认数据库表的所有字段(如company_id)都存在,且数据类型与结构体属性对应(例如companyId是Int类型,表中字段也应为整数类型)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 18:43:15