2

我正在为如何返回包含父关系的模型而苦苦挣扎,同时将急切加载的模型映射到不同的形式。

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

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?这是否意味着我必须为 制作一个 DTO Course,将我的数组从 映射[Course][PublicCourse],复制所有属性,在模型更改时使它们保持同步Course等?

这似乎是很多样板,未来有很大的错误空间。很想听听是否有更好的选择。

4

2 回答 2

2

您可以通过首先对原始模型进行编码,然后将其解码为具有较少字段的结构来做到这一点。因此,对于要转换为Course存储的实例,您将执行以下操作:coursePublicCourse

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。

于 2021-07-17T20:37:28.853 回答
1

好的,这个方法怎么样?创建第二个Model,称为Teacher,例如,它被定义为User您要在 API/JSON 中公开的字段的子集,并且具有与以下相同的架构/表名称User

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

  // public fields
}

然后将您的关系更改Course为:

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

您的原始查询将保持不变,但只返回减少的字段集。如果您使用Teacher只读,它肯定会起作用。由于基础表存在,因此无需创建MigrationsTeacher我看不到避免包含 ID 的方法,但这可能不是问题。

于 2021-07-19T15:17:49.127 回答