6

Pivot<U, T>在 Vapor 中,我们可以通过创建对象来创建多对多关系,我们希望将模型链接在一起的位置U和位置。T因此,如果我想创建一个Users 可以有很多Files 并且很多Files 可以属于很多Users 的系统,我会这样关联它们:

var alice = User(name: "Alice")
try! alice.save()
var sales = File(name: "sales.xclx")
try! sales.save()

var pivot = Pivot<User, File>(alice, sales)
try! pivot.save()

我一生无法弄清楚的是如何制作Pivot<User, File>包含其他信息的内容?例如,我想知道这个文件是什么时候与 Alice 关联的,或者她对它有什么权限。

在关系数据库上,Fluent 为该Pivot<User, File>类型创建此表。

+---------+---------+------+-----+---------+----------------+
| Field   | Type    | Null | Key | Default | Extra          |
+---------+---------+------+-----+---------+----------------+
| id      | int(11) | NO   | PRI | NULL    | auto_increment |
| file_id | int(11) | NO   |     | NULL    |                |
| user_id | int(11) | NO   |     | NULL    |                |
+---------+---------+------+-----+---------+----------------+

但我希望能够代表这样的东西:

+---------+---------+------+-----+---------+----------------+
| Field   | Type    | Null | Key | Default | Extra          |
+---------+---------+------+-----+---------+----------------+
| id      | int(11) | NO   | PRI | NULL    | auto_increment |
| file_id | int(11) | NO   |     | NULL    |                |
| user_id | int(11) | NO   |     | NULL    |                |
| date    | date    | NO   |     | NULL    |                |
| perms   | varchar | NO   |     | READ    |                |
+---------+---------+------+-----+---------+----------------+
4

2 回答 2

6

Pivot<U, T>对象可以被认为是像siblings.

如果您想向此表添加自定义字段,您可以创建自己的类来充当枢轴,只要它具有所需的元素:

  • FooBaris 的表名bar_foo(小写,按字母顺序)
  • 至少存在三列:id, bar_id,foo_id

换句话说,由您的数据透视类创建的表必须至少包含Pivot<Foo, Bar>准备工作会创建的元素。

完成此操作后,您可以通过创建和保存枢轴类的实例来创建新的枢轴关系。

.siblings()在使用此数据透视表的模型上调用关系时,Pivot<U, T>仍将创建默认值来执行提取。但是,这不会产生任何问题,因为数据透视表上存在必填字段。

于 2016-11-14T16:21:44.013 回答
4

因此,在遇到 Andy 描述的相同问题并在 Vapor Slack 上寻求解决方案后,我被重定向到这里。

我对 Tanner 提出的解决方案的实现(使用 PostgreSQL)可以在这里找到

关键是Rating型号:

  • 这是一个普通的Model子类
  • 它的entity名称为movie_user(如 Tanner 所述,相关模型的名称按字母顺序排列)
  • 它有字段userId(映射到"user_id")和movieId(映射到"movie_id"),两者都是类型Node
  • 其中prepare(Database)再次使用名称"movie_user"并将 Id 字段定义为Ints。

通过该设置,您可以定义以下关系便利方法:

Movie:所有评分者

extension Movie {
    func raters() throws -> Siblings<User> {
        return try siblings()
    }
}

User:所有分级电影

extension User {
    func ratedMovies() throws -> Siblings<Movie> {
        return try siblings()
    }
}

可以像这样添加电影的新评级(对于用户):

ratings.post() { request in
    var rating = try Rating(node: request.json)
    try rating.save()
    return rating
}

作为Rating模型子类,我们可以直接从请求 JSON 中创建它。这需要客户端发送一个符合Rating类节点结构的 JSON 文档:

{
    "user_id": <the rating users id>,
    "movie_id": <the id of the movie to be rated>,
    "stars": <1-5 or whatever makes sense for your usecase>
}

要获得Rating给定电影的所有实际 s,您似乎必须手动解决关系(至少我认为是这样,也许有人可以给我一个提示,告诉我如何更好地做到这一点):

let ratings = try Rating.query().filter("movie_id", movieId).all()

此外,目前似乎无法以某种方式计算数据库的平均值。我会喜欢这样的工作:

// this is now how it works
let averageRating = try Rating.query().filter("movie_id", movieId).average("stars")

所以我希望这可以帮助任何遇到这个问题的人。感谢所有为 Vapor 项目做出贡献的优秀人士!

感谢@WERUReo 指出创建评级的部分缺失。

于 2017-01-17T10:49:05.077 回答