【问题标题】:Setting property in pivot table in many to many relation在多对多关系中设置数据透视表中的属性
【发布时间】:2021-01-19 08:04:36
【问题描述】:

我已经通过 Vapor 4 中的数据透视表 LocaleSite 设置了多对多关系区域设置 站点。这是有效的,我可以将 Locale 附加到 Site,反之亦然。 在数据透视表中,我添加了一个属性.sortOrder

final class LocaleSite : Model {
    static let schema = "locale+site"
    
    struct FieldKeys {
        static var createdAt: FieldKey { "created_at" }
        static var updatedAt: FieldKey { "updated_at" }
        static var deletedAt: FieldKey { "deleted_at" }
        static var locale: FieldKey { "localeID" }
        static var site: FieldKey { "siteID" }
        static var sortOrder: FieldKey { "sortOrder" }
    }
    
    
    @ID
    var id: UUID?
    
    @Timestamp(key: FieldKeys.createdAt, on: .create)
    var createdAt: Date?

    @Timestamp(key: FieldKeys.updatedAt, on: .update)
    var updatedAt: Date?
    
    @Timestamp(key: FieldKeys.deletedAt, on: .delete)
    var deletedAt: Date?

    @Parent(key: FieldKeys.locale)
    var locale: Locale
    
    @Parent(key: FieldKeys.site)
    var site: Site
    
    @Field(key: FieldKeys.sortOrder)
    var sortOrder: Int

附加区域设置数组时

for locale in locales {
    let _ = site.$locales.attach(locale, on: database)
}

我想在附加时在同一循环中将.sortOrder 设置为某个值(可能通过附加函数?),但在文档中找不到方法。 p>

(目前唯一的解决方法是在附加后查询我的站点或语言环境,并通过与设置.sortOrder 的数据透视表的关系。非常低效...)

添加了包含一些 Calebs 答案的代码示例(见评论)

static func createStdData (site: Site, database : Database) -> EventLoopFuture<Void> {
        return Locale.allLocale(database: database).map { locales in
            var order = 0
            for locale in locales {
                let _ = site.$locales.attach(locale, on: database, edit: { pivot in
                    pivot.sortOrder = order
                })
                order += 1
            }
        }
    }

一旦添加了编辑:我就会收到以下错误:

对实例方法“attach”的调用没有完全匹配

检查蒸气源我发现有一个,但显然语法可能不完全正确...

我也试过了:

let _ = site.$locales.attach(locale, on: database, edit: (LocaleSite){ pivot in
                    pivot.sortOrder = order
                })

但我明白了:

没有更多上下文的表达类型是模棱两可的

【问题讨论】:

    标签: relationship vapor vapor-fluent


    【解决方案1】:

    您想为.sortOrder 属性分配什么值将改变您设置该值的方式。根据您的问题,我将假设每个枢轴都应该有一个.sortOrder,它比上一个大1

    为此,我们首先必须在开始循环之前保存最后一个枢轴。这是相当直截了当的:

    let last = LocaleSite.query(on: database).sort(\.$sortOrder, .descending).first()
    

    此查询将结果从最高 .sortOrder 到最低排序,因此第一个将具有最高值。我们现在可以映射该结果。如果我们得到一个模型,我们将基于它的新的.sortOrder 值;否则,我们就从0开始。

    let sortOrder = last.map { pivot in
        return pivot?.sortOrder ?? 0
    }
    

    现在我们将在结果上调用.flatMap。在 .flatMap 闭包中,我们将遍历您要使用 Array.map 插入的 Locale 模型,并将每个 Locale 附加到站点。现在,.attach 方法具有 a handy closure,您可以传入它,您可以使用它在新的数据透视模型插入数据库之前对其进行编辑。我们将使用该闭包来设置枢轴的.sortOrder 值。

    sortOrder.flatMap { order in
        locales.enumerated().map { offset, locale in
            site.$locales.attach(locale, on: database, { pivot in 
                pivot.sortOrder = (order + 1) + offset
            })
        }.flatten(on: database.eventLoop)
    }
    

    * 所有代码都是在我脑海中写下的,未经测试,因此可能需要修改才能正常工作

    【讨论】:

    • 太好了,这对我帮助很大。对于添加的每个新站点,您的实现 atm 有点矫枉过正,有一个新的“sortOrder”,所以我可以从我的本地 var order = 0 开始(但你的代码的那部分将来也会变得很方便,我敢肯定)。但是,我遇到了 Xcode 无法编译的“编辑”闭包问题。可以理解,因为您将其写在脑海中,但是您能否快速查看问题所在。我将我的代码添加到原始帖子中。
    • @Glenn 首先,您应该将for-in 循环替换为.map {}.flatten(on:),以确保正确处理期货。至于编译器错误,看来我错过了您没有使用edit 参数标签。我已经更新了我的答案以反映这一点。
    猜你喜欢
    • 2016-08-16
    • 1970-01-01
    • 2015-02-11
    • 2023-02-05
    • 2018-09-23
    • 2021-05-31
    • 2020-07-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多