2016-11-12 134 views
3

在Vapor中,我们可以通过创建一个Pivot<U, T>对象来创建多对多关系,其中UT是我们想要链接在一起的模型。所以,如果我想创建一个系统,User S可有许多File S和许多File S可属于许多User S,我想他们这样的关联:如何将附加信息添加到数据透视表(使用Fluent)?

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 |    | 
+---------+---------+------+-----+---------+----------------+ 

回答

5

Pivot<U, T>对象可以被认为像siblings枢转关系所要求的“最低限度”的字段。

如果要自定义字段添加到该表中,你可以创建自己的类,只要它具有所需的元件用作枢轴:

  • Foo表名和Barbar_foo(小写,按字母顺序排列)
  • 至少存在的三列:idbar_idfoo_id

换句话说,第由您的枢轴类创建的表必须至少有一个Pivot<Foo, Bar>准备将创建的元素。

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

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

+0

我认为这是一个很好的答案,但仍有一些问题。你说创建一个新的类作为一个枢纽,这是否意味着我应该继承它?如果你留下一个小例子,我会很感激。 –

+0

由于它不是“开放”,因此无法继承它。 Do:class MyPivot:Model {} – tanner0101

+0

那么,这的确回答说我不得不基于Model创建自己的Pivot,而不是子类化'Pivot'。猜猜我会进一步探索这个想法,看看它是如何发展的。 –

3

所以在遇到安迪所描述的相同问题并要求解决蒸汽松弛问题之后,我在这里重定向了。

我实现由坦纳提出的解决方案中(使用PostgreSQL),可以发现here

的关键是Rating型号:

  • 这是一个普通的Model
  • 它有一个entitymovie_user(如Tanner所述,相关型号的名称按字母顺序排列)
  • 它有字段userId(映射到"user_id")和movieId(映射到"movie_id"),都是Node类型。
  • in 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是Model子类,我们可以直接从请求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■对于给定的电影,你似乎有手动解决关系(至少我是这么认为的,也许有人可以给我如何做这更好的提示):

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项目做出贡献的精彩人物!

Thx to @WERUreo用于指出创建评分的部分缺失。

+0

我仍然有一个问题,您如何添加评分?我看到有一条POST路由用于评级,但是您需要通过哪些JSON才能为特定用户的特定电影添加评级? – WERUreo

+1

thx指出了这一点。我更新了答案。基本上,你只是发布整个关系:'user_id','movie_id','stars'。但这只是其中一种方式。你也可以像'POST/users//movies/ {“stars”:4}'(或其他方式),然后在请求处理程序中组装关系。 – floriankrueger