Vapor 4:如何将急切加载的父关系映射为不同的格式?

问题描述 投票:0回答:3

我在如何返回包含父关系的模型,同时将急切加载的模型映射到不同的形式方面遇到了一些困难。

让我们考虑以下 2 个模型:

Course
User

final class Course: Model, Content {
  static let schema = "courses"

  @ID(key: .id)
  var id: UUID?

  @Field(key: "name")
  var name: String

  @Parent(key: "teacher_id")
  var teacher: User

  init() { }
}

final class User: Model, Content {
  static let schema = "users"

  @ID(key: .id)
  var id: UUID?

  @OptionalField(key: "avatar")
  var avatar: String?

  @Field(key: "name")
  var name: String

  @Field(key: "private")
  var somePrivateField: String

  init() { }
}

我有一条像这样的路线,它返回一组课程:

func list(req: Request) throws -> EventLoopFuture<[Course]> {
  return Course
    .query(on: req.db)
    .all()
}

生成的 JSON 看起来像这样:

[
  {
    "id": 1,
    "name": "Course 1",
    "teacher": {
      "id": 1
    }
]

我想要的是返回教师对象,通过在查询中添加

.with(\.$teacher)
就可以很容易地实现这一点。 Vapor 4 确实让这一切变得非常简单!

[
  {
    "id": 1,
    "name": "Course 1",
    "teacher": {
      "id": 1,
      "name": "User 1",
      "avatar": "https://www.example.com/avatar.jpg",
      "somePrivateField": "super secret internal info"
    }
]

我的问题是:返回整个

User
对象,几乎包含所有字段,甚至是我不想公开的字段。

将教师信息转换为不同版本的

User
模型(例如
PublicUser
)的最简单方法是什么?这是否意味着我必须为
Course
创建 DTO,将数组从
[Course]
映射到
[PublicCourse]
,复制所有属性,在
Course
模型更改时保持同步,等等?

这看起来像是很多样板,将来有很大的出错空间。很想听听是否有更好的选择。

swift vapor vapor-fluent
3个回答
2
投票

您可以通过首先对原始模型进行编码,然后将其解码为具有较少字段的结构来实现此目的。因此,对于存储在

Course
中的
course
实例要转换为
PublicCourse
,您可以这样做:

struct PublicCourse: Decodable {
    //...
    let teacher: PublicUser
    //...
}

let course:Course = // result of Course.query including `with(\.$teacher)`
let encoder = JSONEncoder()
let decoder = JSONDecoder()
let data = try encoder.encode(course)
let publicCourse = try decoder.decode(PublicCourse.self, from: data)

注意结构中的

PublicUser
字段。如果这是精简版本,您可以一次性生成最小的 JSON。


1
投票

好的,这个方法怎么样?创建第二个

Model
,称为
Teacher
,它被定义为您想要在 API/JSON 中公开的
User
中的字段子集,并且具有与
User
相同的架构/表名称:

final class Teacher: Model, Content {
  static let schema = "users"

  // public fields
}

然后将

Course
中的关系更改为:

@Parent(key: "teacher_id")
var teacher: Teacher

您的原始查询将保持不变,但仅返回减少的字段集。如果您使用

Teacher
只读,它肯定会起作用。无需为
Migrations
创建
Teacher
,因为基础表已存在。我找不到避免包含 ID 的方法,但这可能不是问题。


-1
投票

我可以听听你的新解决方案吗?其他方法

© www.soinside.com 2019 - 2024. All rights reserved.