如何向 Pivot 添加附加信息(使用 Fluent)?
Posted
技术标签:
【中文标题】如何向 Pivot 添加附加信息(使用 Fluent)?【英文标题】:How do I add additional information to a Pivot (using Fluent)? 【发布时间】:2016-11-12 17:24:47 【问题描述】:在 Vapor 中,我们可以通过创建 Pivot<U, T>
对象来创建多对多关系,其中 U
和 T
是我们想要链接在一起的模型。所以如果我想创建一个User
s 可以有很多File
s 并且很多File
s 可以属于很多User
s 的系统,我会这样关联它们:
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 | |
+---------+---------+------+-----+---------+----------------+
【问题讨论】:
【参考方案1】:Pivot<U, T>
对象可以被认为是像siblings
这样的透视关系的“最低限度”必需字段。
如果您想在此表中添加自定义字段,您可以创建自己的类来充当枢轴,只要它具有所需的元素:
Foo
和 Bar
的表名称为 bar_foo
(小写,按字母顺序排列)
至少存在三列:id
、bar_id
、foo_id
换句话说,您的数据透视类创建的表必须至少包含 Pivot<Foo, Bar>
准备创建的元素。
完成此操作后,您可以通过创建和保存枢轴类的实例来创建新的枢轴关系。
当在使用此数据透视表的模型上调用 .siblings()
关系时,仍将创建默认的 Pivot<U, T>
来执行提取。但是,这不会产生任何问题,因为数据透视表上存在必填字段。
【讨论】:
我认为这是一个很好的答案,但仍然存在一些问题。你说创建一个新类作为一个支点,这是否意味着我应该对它进行子类化?如果您留下一个小例子,我将不胜感激。 不能继承它,因为它不是open
。做:class MyPivot: Model
嗯,这确实回答了我必须基于模型创建自己的 Pivot,而不是继承 Pivot
。我想我会进一步探索这个想法,看看它是如何进行的。
如果我们要创建模型以便使用 Pivot 函数,我们将不得不修改数据库中的表名,因为会有一个复数形式的 s
,并且 Pivot 创建一个连接表名而没有 @ 987654335@在最后【参考方案2】:
因此,在遇到 Andy 描述的相同问题并在 Vapor Slack 上寻求解决方案后,我被重定向到这里。
我对 Tanner 提出的解决方案的实现(使用 PostgreSQL)可以找到here
关键是Rating
模型:
Model
子类
它的 entity
名称为 movie_user
(如 Tanner 所述,相关模型的名称按字母顺序排列)
它有userId
(映射到"user_id"
)和movieId
(映射到"movie_id"
)字段,两者都是Node
类型。
在prepare(Database)
中,它再次使用名称"movie_user"
并将Id 字段定义为Int
s。
通过该设置,您可以定义以下关系便利方法:
在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 指出创建评级的部分缺失。
【讨论】:
我还有一个问题是,你如何添加评级?我看到有一个用于评分的 POST 路由,但是您需要传递什么 JSON 才能为来自特定用户的特定电影添加评分? 感谢您指出这一点。我更新了答案。基本上,您只是发布整个关系:user_id
、movie_id
、stars
。但这只是一种方法。你也可以选择POST /users/<user_id>/movies/<movie_id> "stars": 4
(或其他方式),然后在请求处理程序中组装关系。以上是关于如何向 Pivot 添加附加信息(使用 Fluent)?的主要内容,如果未能解决你的问题,请参考以下文章