【问题标题】:Understanding Migrations in Vapor-Fluent (Server side Swift)了解 Vapor-Fluent 中的迁移(服务器端 Swift)
【发布时间】:2019-09-20 12:01:39
【问题描述】:

我正在使用 Vapor 框架在 Swift 中编写一个 Web 服务。

我的模型名为Item。最初它只有 name 和 id 属性。

typealias VaporModel = Content & PostgreSQLModel & Parameter
final class Item: VaporModel {
    var id: Int?
    var name: String
}

在我为模型配置控制器并添加路由后,当我点击 post Item 请求时,我收到Model.defaultDatabase is required to use as DatabaseConnectable 的错误。我认为错误是因为我没有在configure.swift 中将Item 添加到Migrations,并且在将ItemPostgreSQLMigration 一致后我也这样做了。

var migrations = MigrationConfig()
migrations.add(model: Item.self, database: .psql)
services.register(migrations)

现在,我可以点击发布请求并在数据库中创建项目。

所以我知道Migration 协议会为模型创建默认架构,并将新表添加到数据库中,并将模型的属性作为列。

现在我想在我的 Item 类中添加一个属性,例如 price。现在,当我点击发布请求时,我收到错误为column "price" of relation "Item" does not exist。 我假设迁移协议将能够识别架构更改和我的表的列(这是我在 iOS 应用程序中使用 Realm 时所习惯的)。但我错了,我通读了 Migration 文档并在迁移中实现了 preparerevert 方法,如下所示。

extension Item: PostgreSQLMigration {
    static func prepare(on conn: PostgreSQLConnection) -> Future<Void> {
        return Database.create(self, on: conn) { creator in
            creator.field(for: \.price)
        }
    }

    static func revert(on connection: PostgreSQLConnection) -> EventLoopFuture<Void> {
        return Future.map(on: connection) { }
    }
} 

我仍然对同样的错误column "price" of relation "Item" does not exist 感到震惊。我在这里想念什么?我的迁移代码是否正确?

另外,我知道如果不对模型进行任何更改,我可以注释掉迁移配置,因为它们不需要在我每次运行服务时都运行。对吗?

【问题讨论】:

    标签: swift postgresql fluent vapor server-side-swift


    【解决方案1】:

    使用您的代码,您还没有添加新的迁移。您已实施手动初始迁移,但初始迁移已按要求运行 (migrations.add(model: Item.self, database: .psql)。要创建新迁移,您需要以下内容:

    struct ItemAddPriceMigration: Migration {
        typealias Database = PostgreSQLDatabase
    
        static func prepare(on conn: PostgreSQLConnection) -> EventLoopFuture<Void> {
    
            return Database.update(Item.self, on: conn) { builder in
                builder.field(for: \.price)
            }
        }
    
        static func revert(on conn: PostgreSQLConnection) -> EventLoopFuture<Void> {
            return conn.future()
        }
    }
    

    然后你需要添加到configure:

    migrations.add(migration: ItemAddPriceMigration.self, database: .psql)

    【讨论】:

    • 我已经尝试过这种方法,但没有成功。您共享的代码没有构建,它是在我将 self 更改为 Item.self 时构建的。然后当我运行该服务时,我收到错误Error raised at top level: ⚠️ PostgreSQL Error: relation "Item" already exists
    • 对不起,这是update,当然不是create。答案已更新。
    • 谢谢。解决了那个错误。我应该如何为新列提供默认值?因为我收到错误column "price" contains null values
    • 假设 priceInt 你会以 1 的价格执行 builder.field(for: \.price, type: .bigint, PostgreSQLColumnConstraint.default(.literal(1)))
    • 现在我想将价格设为双倍/浮动,我可以像上面那样进行迁移并设置默认值,但这会将数据库中的所有项目价格设置为默认值。如何迁移每件商品的价格?
    猜你喜欢
    • 2020-04-08
    • 2019-09-18
    • 2019-08-02
    • 1970-01-01
    • 1970-01-01
    • 2019-08-18
    • 2017-06-13
    • 1970-01-01
    • 2020-08-19
    相关资源
    最近更新 更多