0

下面是我当前如何处理延迟字段参数的示例。

一个Parent类包含一个延迟PageChild对象。子项的分页参数在children字段上定义。我需要能够将分页参数连同父 ID 一起传递给 deferred Fetcher,所以我将它们与父 ID 一起捆绑在一个临时DeferredChildInput对象中,然后将它们传递给Fetcher. 相应DeferredChildResult的返回查询的结果 (the Page[Child]) 和 the DeferredChildInput(use in the HasId)。

问题是,有没有更好的方法将字段参数和父 id 传递给 deferred Fetcher

case class Page[T](
  data: Seq[T],
  pageNumber: Int,
  pageSize: Int,
  totalRecords: Long
)

case class Parent(
  id: Long,
  children: Page[Children] // this field is deferred
)

case class Child(
  id: Long
  parentId: Long
)

// the field's query parameters
case class DeferredChildInput(
  parentId: Long,
  pageNumber: Int,
  pageSize: Int
)

// used to temporarily hold the result of the deferred resolution
case class DeferredChildResult(
  input: DeferredChildInput // this is used to resolve the HasId check
  page: Page[Child] // this is what we really want
)

trait ChildService {
  def getChildrenByParentId(
    parentId: Long,
    pageNumber: Int,
    pageSize: Int
  ): Page[Child]
}

val childFetcher: Fetcher[MyContext, DeferredChildResult, DeferredChildResult, DeferredChildInput] = Fetcher {
    (ctx: MyContext, inputs: Seq[DeferredChildInput]) =>
      val futures = inputs.map { input =>
        ctx.childService.getChildrenByParentId(
          input.parentId,
          input.pageNumber,
          input.pageSize
        ).map { childPage =>
          DeferredChildResult(input, childPage)
        }
      }

    Future.sequence {
      futures
    }
  }(HasId(_.input))
}

val ChildObjectType = derivedObjectType[Unit, Child]()

val ParentObjectType = deriveObjectType[Unit, Parent](
  ReplaceField(
    fieldName = "children",
    field = Field(
      name = "children",
      fieldType = PageType(childObjectType),
      arguments = List(
        Argument(
          name = "pageNumber",
          argumentType = IntType
        ), Argument(
          name = "pageSize",
          argumentType = IntType,
        )
      ),
      resolve = ctx => {
        // bundle the field/query parameters into a single input object
        val input = DeferredChildInput(
          parentId = ctx.value.id,
          pageNumber = ctx.args[Int]("pageNumber"),
          pageSize = ctx.args[Int]("pageSize")
        )

        DeferredValue(childFetcher.defer(input)).map { results =>
          results.page
        }
      }
    )
  )
)
4

2 回答 2

2

在这种情况下,您并没有真正从使用提取器中受益,它只会增加数据提取机制的复杂性。例如,结果不太可能被缓存和重用。您还分别解决了每个DeferredChildInput问题,这违背了获取器的主要目的(即批量获取数据,inputs在单个请求/数据库交互中获取所有数据)。

我建议在这种情况下完全避免使用提取器,并直接从解析函数中获取页面数据。Fetchers 并不真正支持分页。在某些情况下,在解析函数中获取实体的 ID,然后使用 fetcher 根据已知的 ID 列表获取实体数据可能是可行的。但据我所知,您的情况并非如此。

于 2018-01-24T19:51:25.643 回答
0

此外,当使用解析器并返回 N 个父对象时,您最终会为每个子对象获取 N+1 次,这比获取 n 页子对象并按父对象 ID 分组要慢得多。

于 2018-01-25T00:27:50.820 回答