给出以下示例模型(选择2个显示1-n关系的简单示例):
final class Company: MySQLModel {
var id: Int?
var name: String
}
final class Client: MySQLModel {
var id: Int?
var attr1: Int
var attr2: String
var companyId: Company.ID
static func prepare(on connection: MySQLDatabase.Connection) -> Future<Void> {
return Database.create(self, on: connection, closure: { builder in
try addProperties(to: builder)
builder.addReference(from: \.companyId, to: \Company.id, actions: .update)
})
}
}
Run Code Online (Sandbox Code Playgroud)
有没有办法获取和返回JOINED查询的结果(例如:公司 - 客户端//一对多)而无需原始查询?我尝试使用Query和Relationships但是没有办法一次性获取所有这些.
理想情况下,返回的数据将具有如下嵌套结构:
预期:
{
"name": "Alice",
"id": 0000000001,
"company": {
"id": 11111111,
"name": "Stack Overflow"
}
}
Run Code Online (Sandbox Code Playgroud)
我确实设法通过使用额外的结构(称为Wrapper,Box,Merged等)使其"工作"来保存所有实体,最后使用makeJSON将其返回到Controller内部.
let query = try db.query(Client.self)
.filter(\.attr1 > 123)
.filter(\.attr2 == "abc")
let client = try query.first()
// client.company is just an attribute of Client that uses
// the *parent* method to retrieve it
if let client = client, let company = try client.company.get() {
// others uses *children* method
let others = try client.others.limit(5).all()
let companyJSON = company.dictionary! // dictionary returns [String:Any] for any Encodable
let clientJSON = client.dictionary!
let merged = clientJSON.merging([ "company": companyJSON ], uniquingKeysWith: { (first, _) in first })
return merged
}
Run Code Online (Sandbox Code Playgroud)
使用包装器实体是唯一的方法(不使用原始查询)?处理多级结果将非常繁琐.
编辑:我已经找到了一个相关问题是否可以访问Vapor联接表中的字段?但答案并没有像我想要的那样工作.
Edit2:我最近迁移到Vapor3,因此新代码.我认为Vapor2的想法是一样的,但是由于Vapor3引入了Codable支持,你必须编写更多的代码.
我不确定这是否完全是您正在寻找的,但我想我正在尝试做类似的事情。我想显示用户表及其关联的身份验证令牌。这是以标准方式设置的,在 Fluent 中设置父子(一对多)关系。我最终做了以下效果很好的事情
func getUsersHandler(_ req: Request) throws -> Future<View> {
return User.query(on: req).all().flatMap(to: View.self) { users in
let tokenFutures = try users.map {
return try $0.authTokens.query(on: req).all()
}
return tokenFutures.flatMap(to: View.self) { tokensByUser in
let usersAndTokens = zip(users, tokensByUser).map {
return UserAndTokens(user: $0, tokens: $1.map { $0.token})
}
let listUsersCtx = ListUsersContext(usersAndTokens: usersAndTokens)
return try req.leaf().render("users", listUsersCtx)
}
}
}
Run Code Online (Sandbox Code Playgroud)
我刚刚学习 Vapor,所以我不知道这是否是一个很好的解决方案。通过让用户承诺解析,然后让每个用户->令牌承诺解析,一切都保持异步,直到最后我将所有已解析的内容打包在可编码的 ListUsersContext 结构中
| 归档时间: |
|
| 查看次数: |
1317 次 |
| 最近记录: |