GRDB.swift 数据库框架从5.x升级到6.x的完整迁移指南

GRDB.swift 数据库框架从5.x升级到6.x的完整迁移指南

GRDB.swift groue/GRDB.swift: 这是一个用于Swift数据库访问的库。适合用于需要使用Swift访问SQLite数据库的场景。特点:易于使用,具有高效的数据库操作和内存管理,支持多种查询方式。 GRDB.swift 项目地址: https://gitcode.com/gh_mirrors/gr/GRDB.swift

前言

GRDB.swift 是一个优秀的 Swift 数据库框架,它提供了简洁的 API 来操作 SQLite 数据库。随着版本 6 的发布,框架引入了一些重要的改进和变化。本文将全面解析从 GRDB 5 升级到 GRDB 6 需要注意的所有关键点,帮助开发者顺利完成迁移。

升级前的准备工作

在开始升级前,建议开发者先完成以下准备工作:

  1. 确保当前使用的是 GRDB 5 的最新稳定版本
  2. 修复所有已存在的弃用警告
  3. 备份项目代码

新版本要求

GRDB 6 对开发环境提出了更高的要求:

  • Swift 版本:最低要求 Swift 5.7(之前是 5.3)
  • Xcode 版本:需要 Xcode 14.0 或更高版本(之前是 12.0)
  • 操作系统版本
    • iOS 11.0+(保持不变)
    • macOS 10.13+(之前是 10.10)
    • tvOS 11.0+(保持不变)
    • watchOS 4.0+(之前是 2.0)
  • SQLite 版本:3.19.3+(之前是 3.8.5)

主要关联类型的变化

GRDB 6 利用了 Swift 5.7 引入的主要关联类型特性(SE-0346),这使得请求协议的扩展更加简洁优雅。

请求协议扩展的改进

旧版本写法:

extension DerivableRequest where RowDecoder == Book {
    func orderByTitle() -> Self {
        order(Column("title").collating(.localizedCaseInsensitiveCompare))
    }
}

新版本写法:

extension DerivableRequest<Book> {
    func orderByTitle() -> Self {
        order(Column("title").collating(.localizedCaseInsensitiveCompare))
    }
}

查询接口请求的改进

得益于 SE-0361 改进,QueryInterfaceRequest 的扩展也得到了简化:

extension QueryInterfaceRequest<Player> {
    func selectID() -> QueryInterfaceRequest<Int64> {
        selectPrimaryKey()
    }
}

记录(Record)相关的重要变更

GRDB 6 对记录协议进行了重构,以下是需要注意的关键变化:

1. 可抛出错误的初始化方法

FetchableRecord.init(row:) 现在可以抛出错误:

let player = try Player(row: row)  // 必须添加 try 关键字

对于继承 Record 类的子类,需要更新初始化方法:

class Player: Record {
    required init(row: Row) throws {
        self.id = row["id"]
        self.name = row["name"]
        try super.init(row: row)  // 调用父类方法也需要 try
    }
}

2. 可抛出错误的编码方法

EncodableRecord.encode(to:) 现在也可以抛出错误:

class Player: Record {
    override func encode(to container: inout PersistenceContainer) throws {
        container["id"] = id
        container["name"] = name
    }
}

受此影响,以下 API 现在也需要处理错误:

let dictionary = try player.databaseDictionary
let changes = try newPlayer.databaseChanges(from: oldPlayer)

3. didInsert 方法签名变更

didInsert 方法的参数从 (with:for:) 变为了 InsertionSuccess 结构体:

struct Player: MutablePersistableRecord {
    var id: Int64?
    
    mutating func didInsert(_ inserted: InsertionSuccess) {
        id = inserted.rowID
    }
}

对于 Record 子类:

class Player: Record {
    var id: Int64?
    
    override func didInsert(_ inserted: InsertionSuccess) {
        super.didInsert(inserted)  // 必须调用 super
        id = inserted.rowID
    }
}

4. 持久化回调替代重写方法

GRDB 6 引入了"持久化回调"机制来替代直接重写持久化方法的方式。以下方法已被移除:

// 以下方法在 GRDB 6 中已移除
func insert(_ db: Database) throws
func update(_ db: Database, columns: Set<String>) throws
func save(_ db: Database) throws
func delete(_ db: Database) throws -> Bool

替代方案是使用新的回调方法,如 willSavewillInsertdidDelete 等。例如,验证逻辑可以这样实现:

struct Link: PersistableRecord {
    var url: URL
    
    func willSave(_ db: Database) throws {
        if url.host == nil {
            throw ValidationError("url must be absolute.")
        }
    }
}

5. IGNORE 冲突策略的处理

对于使用 IGNORE 冲突策略的情况,GRDB 6 的行为有所变化:

  • didInsert 现在总是会被调用,即使插入被忽略
  • 可以使用 insertAndFetch 方法来检测插入是否成功:
if let insertedPlayer = try player.insertAndFetch(db) {
    // 插入成功
} else {
    // 插入被忽略
}

其他重要变更

  1. 内存数据库初始化可能抛出错误

    let dbQueue = try DatabaseQueue()
    
  2. selectID() 方法被移除: 可以自行实现:

    extension QueryInterfaceRequest<Player> {
        func selectID() -> QueryInterfaceRequest<Int64> {
            selectPrimaryKey()
        }
    }
    
  3. Cursor.isEmpty 变为属性

    if try cursor.isEmpty { ... }
    
  4. 事务钩子重命名

    db.afterNextTransaction { db in
        print("Transaction completed")
    }
    
  5. 数据库游标不再暴露 statement 属性

    let sql = cursor.sql  // 替代 cursor.statement.sql
    

迁移建议

  1. 逐步迁移:不要一次性升级所有代码,可以逐个模块进行迁移
  2. 利用编译器错误:Xcode 的修复建议可以帮助解决大部分语法变更
  3. 测试覆盖:确保有充分的测试来验证迁移后的行为
  4. 查阅文档:遇到问题时参考 GRDB 的官方文档

结语

GRDB 6 带来了许多现代化改进,虽然需要一定的迁移工作,但这些变化使得 API 更加健壮和符合 Swift 的最新特性。通过本文的指导,开发者应该能够顺利完成从 GRDB 5 到 GRDB 6 的升级,并充分利用新版本提供的各种优势。

GRDB.swift groue/GRDB.swift: 这是一个用于Swift数据库访问的库。适合用于需要使用Swift访问SQLite数据库的场景。特点:易于使用,具有高效的数据库操作和内存管理,支持多种查询方式。 GRDB.swift 项目地址: https://gitcode.com/gh_mirrors/gr/GRDB.swift

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

范轩锦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值