刚开始使用Vapor 3和MySQL数据库,我很难搞清楚关系部分.
到目前为止我创建了2个模型:Movie和Actor.A Movie可以有很多Actors而且Actor可以有很多Movies.
Movie 模型:
import Vapor
import FluentMySQL
final class Movie: Codable {
var id: Int?
var name: String
var synopsis: String
var dateReleased: Date
var totalGrossed: Float
init(id: Int? = nil, name: String, synopsis: String, dateReleased: Date, totalGrossed: Float) {
self.id = id
self.name = name
self.synopsis = synopsis
self.dateReleased = dateReleased
self.totalGrossed = totalGrossed
}
}
extension Movie {
var actors: Siblings<Movie, Actor, MovieActor> {
return siblings()
}
}
extension Movie: Content {}
extension Movie: Parameter {}
extension Movie: MySQLModel {}
extension Movie: MySQLMigration {
static func prepare(on conn: MySQLConnection) -> Future<Void> {
return MySQLDatabase.create(self, on: conn) { builder in
builder.field(for: \.id, isIdentifier: true)
builder.field(for: \.name)
builder.field(for: \.synopsis)
builder.field(for: \.dateReleased, type: .date)
builder.field(for: \.totalGrossed, type: .float)
}
}
}
Run Code Online (Sandbox Code Playgroud)
Actor 模型:
import Vapor
import FluentMySQL
final class Actor: Codable {
var id: Int?
var firstName: String
var lastName: String
var fullName: String {
return firstName + " " + lastName
}
var dateOfBirth: Date
var story: String
init(id: Int? = nil, firstName: String, lastName: String, dateOfBirth: Date, story: String) {
self.id = id
self.firstName = firstName
self.lastName = lastName
self.dateOfBirth = dateOfBirth
self.story = story
}
}
extension Actor {
var actors: Siblings<Actor, Movie, MovieActor> {
return siblings()
}
}
extension Actor: Content {}
extension Actor: Parameter {}
extension Actor: MySQLModel {}
extension Actor: MySQLMigration {
static func prepare(on conn: MySQLConnection) -> Future<Void> {
return MySQLDatabase.create(self, on: conn) { builder in
builder.field(for: \.id, isIdentifier: true)
builder.field(for: \.firstName)
builder.field(for: \.lastName)
builder.field(for: \.dateOfBirth, type: .date)
builder.field(for: \.story, type: .text)
}
}
}
Run Code Online (Sandbox Code Playgroud)
而且我还创建了一个MovieActor模型作为MySQLPivot关系:
import Vapor
import FluentMySQL
final class MovieActor: MySQLPivot {
typealias Left = Movie
typealias Right = Actor
static var leftIDKey: LeftIDKey = \.movieID
static var rightIDKey: RightIDKey = \.actorID
var id: Int?
var movieID: Int
var actorID: Int
init(movieID: Int, actorID: Int) {
self.movieID = movieID
self.actorID = actorID
}
}
extension MovieActor: MySQLMigration {}
Run Code Online (Sandbox Code Playgroud)
并将它们添加到configure.swift文件中的migration部分:
var migrations = MigrationConfig()
migrations.add(model: Movie.self, database: .mysql)
migrations.add(model: Actor.self, database: .mysql)
migrations.add(model: MovieActor.self, database: .mysql)
services.register(migrations)
Run Code Online (Sandbox Code Playgroud)
数据库中的所有表都正常创建,但我在调用get all movies服务时没有收到关系.我刚收到Movie的属性:
final class MoviesController {
func all(request: Request) throws -> Future<[Movie]> {
return Movie.query(on: request).all()
}
}
[
{
"id": 1,
"dateReleased": "2017-11-20T00:00:00Z",
"totalGrossed": 0,
"name": "Star Wars: The Last Jedi",
"synopsis": "Someone with a lightsaber kills another person with a lightsaber"
},
{
"id": 3,
"dateReleased": "1970-07-20T00:00:00Z",
"totalGrossed": 0,
"name": "Star Wars: A New Hope",
"synopsis": "Someone new has been discovered by the force and he will kill the dark side with his awesome lightsaber and talking skills."
},
{
"id": 4,
"dateReleased": "2005-12-20T00:00:00Z",
"totalGrossed": 100000000,
"name": "Star Wars: Revenge of the Sith",
"synopsis": "Anakin Skywalker being sliced by Obi-Wan Kenobi in an epic dual of fates"
}
]
Run Code Online (Sandbox Code Playgroud)
非常感谢您的帮助!非常感谢你 :)
Vin*_*nce 11
因此,我相信您期望这种关系能够反映在查询Movie模型时返回的内容中.因此,例如,您希望为电影返回类似这样的内容:
{
"id": 1,
"dateReleased": "2017-11-20T00:00:00Z",
"totalGrossed": 0,
"name": "Star Wars: The Last Jedi",
"synopsis": "Someone with a lightsaber kills another person with a lightsaber",
"actors": [
"id": 1,
"firstName": "Leonardo",
"lastName": "DiCaprio",
"dateOfBirth": "1974-11-11T00:00:00Z",
"story": "Couldn't get an Oscar until wrestling a bear for the big screen."
]
}
Run Code Online (Sandbox Code Playgroud)
但是,将Movie和Actor模型连接为兄弟姐妹只是为了方便您从电影中查询actor,就像actor是Movie模型的属性一样:
movie.actors.query(on: request).all()
Run Code Online (Sandbox Code Playgroud)
上面的那一行返回:Future <[Actor]>
这反过来反过来从Actor对象访问电影:
actor.movies.query(on: request).all()
Run Code Online (Sandbox Code Playgroud)
上面的那一行返回:Future <[Movie]>
如果你想让它在相同的响应中返回电影及其演员,就像我假设你希望它在上面工作一样,我相信最好的方法是创建一个像这样的内容响应结构:
struct MovieResponse: Content {
let movie: Movie
let actors: [Actor]
}
Run Code Online (Sandbox Code Playgroud)
您的"全部"功能现在看起来像这样:
func all(_ request: Request) throws -> Future<[MovieResponse]> {
return Movie.query(on: request).all().flatMap { movies in
let movieResponseFutures = try movies.map { movie in
try movie.actors.query(on: request).all().map { actors in
return MovieResponse(movie: movie, actors: actors)
}
}
return movieResponseFutures.flatten(on: request)
}
}
Run Code Online (Sandbox Code Playgroud)
此函数查询所有电影,然后遍历每个电影,然后使用"actors"兄弟关系来查询该电影的演员.此actor查询为其查询actor的每个影片返回Future <[Actor]>.映射从该关系返回的内容,以便您可以作为[Actor]而不是Future <[Actor]>访问actor,然后将与电影结合的那些作为MovieResponse返回.
这部movieResponseFutures实际上包含的是一组MovieResponse期货:[Future <[MovieResponse]>]
要将这个期货数组转换为由数组组成的单个未来,请使用flatten(on :).等待等待每个单独的期货完成,然后将它们作为单个未来返回.
如果你真的想要在Movie对象json中使用Actor的数组,那么你可以像这样构造MovieResponse结构:
struct MovieResponse: Content {
let id: Int?
let name: String
let synopsis: String
let dateReleased: Date
let totalGrossed: Float
let actors: [Actor]
init(movie: Movie, actors: [Actor]) {
self.id = movie.id
self.name = movie.name
self.synopsis = movie.synopsis
self.dateReleased = movie.dateReleased
self.totalGrossed = movie.totalGrossed
self.actors = actors
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
613 次 |
| 最近记录: |