• 链式调用
    • 遍历查询
    • 联表查询
  • 查询重定向
  • 核心层接口

    本文将介绍 WCDB Swift 的一些高级接口,包括链式调用与联表查询、查询重定向 和 核心层接口。

    链式调用

    在增删查改一章中,已经介绍了通过 DatabaseTableTransaction 操作数据库的方式。它们是经过封装的便捷接口,其实质都是通过调用链式接口完成的。

    1. let select: Select = try database.prepareSelect(of: Sample.self, fromTable: "sampleTable")
    2. let objects: [Sample] = select.where(Sample.Properties.identifier > 1).limit(from: 2, to: 3).allObjects()
    3.  
    4. let delete: Delete = try database.prepareDelete(fromTable: "sampleTable")
    5. .where(Sample.Properties.identifier != 0)
    6. try delete.execute()
    7. print(delete.changes) // 获取该操作删除的行数

    链式接口都以 prepareXXX 开始,根据不同的调用返回 InsertUpdateDeleteSelectRowSelectMultiSelect 对象。这些对象的基本接口都返回其 self,因此可以链式连续调用。最后调用对应的函数使其操作生效,如 allObjectsexecute(with:) 等。

    通过链式接口,可以更灵活的控制数据库操作。

    遍历查询

    1. let select: Select = try database.prepareSelect(of: Sample.self, fromTable: "sampleTable")
    2. .where(Sample.Properties.identifier > 1)
    3. .limit(from: 2, to: 3)
    4. while let object = try select.nextObject() {
    5. print(object)
    6. }

    WCDB Swift 只会获取并生成遍历到的对象。开发者可以在随时中断查询,以避免浪费性能。

    联表查询

    在链式类中,InsertUpdateDeleteSelectRowSelect 都有其对应的增删查改接口。而 MultiSelect 则不同。MultiSelect 用于联表查询,在某些场景下可提供性能,获取更多关联数据等。以下是联表查询的示例代码:

    1. try database.create(table: "sampleTable", of: Sample.self)
    2. try database.create(table: "sampleTableMulti", of: SampleMulti.self)
    3.  
    4. let multiSelect = try database.prepareMultiSelect(
    5. on:
    6. Sample.Properties.identifier.in(table: "sampleTable"),
    7. Sample.Properties.description.in(table: "sampleTable"),
    8. SampleMulti.Properties.identifier.in(table: "sampleTableMulti"),
    9. SampleMulti.Properties.description.in(table: "sampleTableMulti"),
    10. fromTables: tables
    11. where: Sample.Properties.identifier.in(table: "sampleTable") == SampleMulti.Properties.identifier.in(table: "sampleTableMulti")
    12. )
    13. while let multiObject = try multiSelect.nextMultiObject() {
    14. let sample = multiObject["sampleTable"] as? Sample
    15. let sampleMulti = multiObject["sampleTableMulti"] as? SampleMulti
    16. // ...
    17. }

    该查询将 "sampleTable" 和 "sampleTableMulti" 表联合起来,取出它们中具有相等 identifier 值的数据。多表查询时,所有同名字段都需要通过 in(table:) 接口指定表名,否则会因为无法确定其属于哪个表从而出错。查询到的 multiObject 是表名到对象的映射,取出后进行类型转换即可。

    查询重定向

    查询的数据有时候不是字段本身,但仍需将其取出为对象时,可以使用查询重定向。它可以将查询接口重定向到一个指定字段,从而简化操作。

    1. let object = try database.getObject(on: Sample.Properties.identifier.max().as(Sample.Properties.identifier),
    2. fromTable: "sampleTable")
    3. print(object.identifier)

    示例代码查询了 identifier 的最大值,然后重新定向其到 Sampleidentifier 字段,因此可以直接以对象的形式取出该值。

    核心层接口

    在之前的所有教程中,WCDB Swift 通过其封装的各种接口,简化了最常用的增删查改操作。但 SQL 的操作千变万化,仍会有部分功能无法通过便捷接口满足。此时则可以使用核心层接口。核心层接口通过 CoreStatement,其本质 SQLite C 接口部分接口的封装,结合语言集成查询可以实现几乎所有 SQL 能够完成的操作。

    以下是通过 CoreStatement 获取数据的示例代码。

    1. // 1. 创建 Statement
    2. let statement = StatementSelect().select(Column.any).from("sampleTable")
    3.  
    4. // 2. 创建 CoreStatement
    5. let coreStatement = try database.prepare(statement)
    6.  
    7. // 3. 逐步执行 CoreStatment
    8. while try coreStatement.step() {
    9. // 4. 获取值
    10. let identifier: Int? = coreStatement.value(atIndex: 0)
    11. let description: String? = coreStatement.value(atIndex: 1)
    12. // ...
    13. }
    14. // 5. 释放 CoreStatement。其 deinit 时也会自动释放
    15. // try coreStatement.finalize()

    以下是通过 CoreStatement 写入数据的示例代码。

    1. // 1. 创建 Statement
    2. let bindingParameters = Array(repeating: Expression.bindingParameter, count: 2)
    3. let statement = StatementInsert().insert(intoTable: "sampleTable").values(bindingParameters)
    4.  
    5. // 2. 创建 CoreStatement
    6. let coreStatement = try database.prepare(statement)
    7.  
    8. for i in 0..<10 {
    9. // 3. 绑定值
    10. coreStatement.bind(i, toIndex: 1)
    11. coreStatement.bind("\(i)", toIndex: 2)
    12. // 4. 逐步执行 CoreStatement
    13. try coreStatement.step()
    14. // 5. 重置绑定
    15. try coreStatement.reset()
    16. }
    17. // 6. 释放 CoreStatement。其 deinit 时也会自动释放
    18. // try coreStatement.finalize()