2016-11-12 136 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