如何让苦艾酒和数据加载器协同工作



我有一个GraphQL API,它使用传统的解析函数可以很好地工作。我的目标是消除N+1问题。

为此,我决定使用Dataloader。我已经完成了这些步骤,以使应用程序运行:


  1. 我在上下文模块中添加了这两个函数:
defmodule Project.People do
# CRUD...
def data, do: Dataloader.Ecto.new(Repo, query: &query/2)
def query(queryable, _params) do
queryable
end
end
  1. 我将context/1plugins/0添加到Schema模块,并更新了查询的解析器:
defmodule ProjectWeb.GraphQL.Schema do
use Absinthe.Schema
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
alias ProjectWeb.GraphQL.Schema
alias Project.People
import_types(Schema.Types)
query do
@desc "Get a list of all people."
field :people, list_of(:person) do
resolve(dataloader(People))
end
# Other queries...
end
def context(context) do
loader =
Dataloader.new()
|> Dataloader.add_source(People, People.data())
Map.put(context, :loader, loader)
end
def plugins, do: [Absinthe.Middleware.Dataloader | Absinthe.Plugin.defaults()]
end

官方教程中没有给出其他步骤。我的:person对象如下所示:

@desc "An object that defines a person."
object :person do
field :id, :id
field :birth_date, :date
field :first_name, :string
field :last_name, :string
field :pesel, :string
field :second_name, :string
field :sex, :string
# field :addresses, list_of(:address) do
#   resolve(fn parent, _, _ ->
#     addresses = Project.Repo.all(Ecto.assoc(parent, :addresses))
#     {:ok, addresses}
#   end)
#   description("List of addresses that are assigned to this person.")
# end
# field :contacts, list_of(:contact) do
#   resolve(fn parent, _, _ ->
#     contacts = Project.Repo.all(Ecto.assoc(parent, :contacts))
#     {:ok, contacts}
#   end)
#   description("List of contacts that are assigned to this person.")
# end
end

评论的部分是在没有dataloader的情况下工作的解析器,不会导致问题。

当我尝试查询时:

{
people { 
id
}
}

我得到这个:

Request: POST /graphiql
** (exit) an exception was raised:
** (Dataloader.GetError)   The given atom - :people - is not a module.
This can happen if you intend to pass an Ecto struct in your call to
`dataloader/4` but pass something other than a struct.

我不完全理解错误消息,因为我将模块传递给dataloader/1,但找不到解决方案。可能是什么情况?

我已经成功地实现了这一点-以下是如何做到的:

dataloader本身不知道从数据库中提取什么,它只了解关联。因此,dataloader(People)只能是object块的一部分,而不是query块。

换句话说:

defmodule ProjectWeb.GraphQL.Schema do
use Absinthe.Schema
import Absinthe.Resolution.Helpers, only: [dataloader: 1]
alias ProjectWeb.GraphQL.Schema
alias Project.People
import_types(Schema.Types)
query do
@desc "Get a list of all people."
field :people, list_of(:person) do
resolve(&StandardPerson.resolver/2)
end
# Other queries...
end
def context(context) do
loader =
Dataloader.new()
|> Dataloader.add_source(People, People.data())
Map.put(context, :loader, loader)
end
def plugins, do: [Absinthe.Middleware.Dataloader | Absinthe.Plugin.defaults()]
end

@desc "An object that defines a person."
object :person do
field :id, :id
field :birth_date, :date
field :first_name, :string
field :last_name, :string
field :pesel, :string
field :second_name, :string
field :sex, :string
field :addresses, list_of(:address) do
resolve(dataloader(People))
description("List of addresses that are assigned to this person.")
end
field :contacts, list_of(:contact) do
resolve(dataloader(People))
description("List of contacts that are assigned to this person.")
end
end

最新更新