【问题标题】:How do i make GRDB ignore a stored variable when fetching from SQLite?从 SQLite 获取时,如何让 GRDB 忽略存储的变量?
【发布时间】:2022-01-31 16:15:16
【问题描述】:

我有一个同时采用TableRecordFetchableRecord 的课程。我标记了 GRDB 提供的自动查询生成的优势,我只提供表名,因为它与类名不匹配。但是现在我想添加仅在运行时使用的存储属性,并且我不希望 GRDB 尝试自动获取这些属性。我可以从查询中排除某些变量吗?

这是我的代码:

class Question: Identifiable, Codable, TableRecord, FetchableRecord {
    static var databaseTableName = "questions"
    
    var id: Int?
    var category: Int?
    var code: String?
    var ...
    var ...
    var ...
    var ...
    var selectedAnswer: Int? // This is only used at run-time and not present in the database.
}

我发现了这个:

static var databaseSelection = [Column("id"), Column("category"), Column("code"), ...]

但这需要我手动指定我希望它获取的所有列。我可以做相反的事情,只排除一列(selectedAnswer)吗?

基本上我要找的是这样的:

static var excludedVariables = ["selectedAnswer"]

我通读了文档但找不到任何东西,但我不知道 GRDB,所以我可能错过了一些东西。

【问题讨论】:

    标签: swift grdb


    【解决方案1】:

    我认为这不是一个特定的 GRDB 问题,而更像是一个Codable 问题,即“如何排除一个属性被解码”。因此,您的解决方案可能是明确定义编码键,而不是让 Swift 合成它们:

    enum CodingKeys: String, CodingKey {
      case id, category, code, ...
    }
    

    它仍然需要您定义所有列/属性,但当您想要排除某些属性时,Codable 总是如此。

    【讨论】:

    • 谢谢,但也许我的问题不够具体。我仍然需要 Coding 支持,因为这个类是从 SQLite 加载的,但后来被写入 JSON 并且需要以 JSON 形式保留 selectedAnswer。
    • 啊,好的。在这种情况下,您可能需要实现自己的 init(from:) 方法来覆盖合成的方法。
    【解决方案2】:

    你不需要做任何事情:

    • 默认情况下,GRDB 选择所有列 (SELECT * FROM ...)。如果没有非持久属性的列,则不会获取它(并且不会在生成的 SQL 中插入无效列)。
    • 可选属性从已解码行中不存在的列中解码为nil

    例如:

    import GRDB
    
    var configuration = Configuration()
    configuration.prepareDatabase { db in
        db.trace { print("SQL> \($0)") }
    }
    let dbQueue = DatabaseQueue(configuration: configuration)
    
    struct Player: Identifiable, Codable, TableRecord, FetchableRecord {
        var id: Int64
        var name: String
        var score: Int
        var ignored: Int? // Has no matching column in the database
    }
    
    try dbQueue.write { db in
        try db.create(table: "player") { t in
            t.autoIncrementedPrimaryKey("id")
            t.column("name", .text).notNull()
            t.column("score", .integer).notNull()
        }
    
        try db.execute(sql: """
            INSERT INTO player (id, name, score) VALUES (NULL, 'Arthur', 100);
            INSERT INTO player (id, name, score) VALUES (NULL, 'Barbara', 1000);
            """)
        
        // SELECT * FROM player
        let players = try Player.fetchAll(db)
    
        // [Player(id: 1, name: "Arthur", score: 100, ignored: nil),
        //  Player(id: 2, name: "Barbara", score: 1000, ignored: nil)]
        print(players)
    }
    

    【讨论】:

    • 那为什么我一添加一个不作为列存在的变量就开始崩溃?我可以稍后检查确切的消息,但我认为这是关于不存在的列的一些 SQL 错误。
    • 上面提供的示例代码回答了这个问题,并且不会崩溃(您可以粘贴代码并运行它)。如果您还有其他问题,请参阅stackoverflow.com/help/minimal-reproducible-example
    猜你喜欢
    • 2015-10-03
    • 2018-07-24
    • 2021-11-14
    • 2012-10-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-30
    • 2016-06-05
    相关资源
    最近更新 更多