Phoenix/Elixir - 协议 Enumerable 未实现

Posted

技术标签:

【中文标题】Phoenix/Elixir - 协议 Enumerable 未实现【英文标题】:Phoenix/Elixir - protocol Enumerable not implemented 【发布时间】:2017-07-01 15:49:27 【问题描述】:

免责声明:我是 Phoenix 和 Elixir 的新手

我正在尝试创建一个非常基本的 API,用于查询后端 mysql 数据库并获取单个记录、编码为 JSON 并返回。

我有一个现有的 MySQL 数据库,它是现有 Python 应用程序的一部分,我想在 Phoenix 中重构该应用程序,但保持数据库不变,并让新的 Phoenix 应用程序连接并查询它。

所以由于数据库已经存在并且我没有创建新架构,因此我为每个表定义了我的架构并将它们放在我的 /lib 目录中。

我正在尝试查询 TestResultDetail 表并获取给定序列号的最后一条记录。 TestResultDetail 表与包含父记录的 TestResult 表具有多对一关系。

我收到以下错误,不知道如何补救:

在 GET /api/v2/opt/last-result/113325-1002 处出现 Protocol.UndefinedError #Ecto.Query 未实现协议可枚举

应用结构:

这是我对发生错误的看法:

defmodule Webservices.OPTView do
  use Webservices.Web, :view

    def render("index.json", %results: results) do
      %
      results: Enum.map(results, &result_json/1)
      
    end

    def render("last.json", %results: results) do
      %
      results: Enum.each(results, &last_result_json/1)
      
    end

    def result_json(result) do
      %
      id: result.id,
      serial: result.serial,
      date_added: result.date_added
      
    end

    def last_result_json(result) do
      %
      serial: result.serial,
      station: result.station,
      stage: result.stage,
      operator: result.operator,
      revision: result.sequence_rev
      
    end

end

这是我的架构:(lib/opt_test_result_detail.ex)

defmodule Webservices.TestResultDetail do
  use Ecto.Schema
  import Ecto.Query

  schema "test_result_detail" do
    field :status_id, :integer
    field :station_id, :integer
    field :stage_id, :integer
    field :operator_id, :integer
    field :failstep, :string
    field :shift, :integer
    field :sequence_rev, :integer
    field :date_added, Ecto.Date
    field :date_timestamp, Ecto.DateTime
    field :date_time, Ecto.Time
    field :stage_order, :integer
    field :serial_number, :string
    field :is_retest, :integer
    field :retest_reason, :string

    has_many :result_id, Webservices.TestResult
  end

  # fetch last recorded test result for a serial
  def last_completed_test(serial) do
    from c in Webservices.TestResultDetail,
      join: t in TestResult, on: t.id == c.result_id,
      select: t.serial, c.station_id, c.stage_id, c.operator_id, c.sequence_rev,
    where: t.serial == ^serial,
    order_by: [desc: c.id],
    limit: 1
  end

end

我的控制者:

defmodule Webservices.OPTController do
    use Webservices.Web, :controller

    alias Webservices.Router
    import Webservices.Router.Helpers

# this is the main controller

#    def index(conn, %"serial" => serial) do
#        import Ecto.Query
#
#        results = Webservices.TestResult
#        |> where([p], p.serial == serial)
#        |> Webservices.Repo.all
#
#        render(conn, "index.json", results: results)
#
#    end


    def last(conn, %"serial" => serial) do
        import Ecto.Query

        results = Webservices.TestResultDetail.last_completed_test(serial)

        render(conn, "last.json", results: results)
    end
end

【问题讨论】:

显示控制器。可能您忘记通过Repo.one 传递查询。 抱歉,更新了我的控制器 【参考方案1】:

在您看来,您忘记拨打Repo.one/1

results = Webservices.TestResultDetail.last_completed_test(serial)
          |> Repo.one

不过,稍微重构一下代码会更好

def last_completed_test(serial) do
  from c in __MODEL__,
    join: t in assoc(c, :results)
    order_by: [desc: c.id],
    where: t.serial == ^serial
end

我也相信这一点:

has_many :result_id, Webservices.TestResult

应该是这样的

belongs_to :results, Webservices.TestResult

【讨论】:

对于 Repo.one 的更改,您提到了我的观点,它不应该在控制器中吗?假设您确实是这个意思,我更新了我的控制器(见上文)并且我在 GET /api/v2/opt/last-result/113325-1002 函数 TestResult.__schema__/1 处收到以下错误 UndefinedFunctionError 未定义(模块 TestResult 是不可用) 另外请注意,TestResultDetail 模型与 TestResult 表具有 FK (ManyToOne) 关系。每个父 TestResult 记录会有很多 TestResultDetail 记录。

以上是关于Phoenix/Elixir - 协议 Enumerable 未实现的主要内容,如果未能解决你的问题,请参考以下文章

从 Phoenix / Elixir GET 函数中调用 Typescript 函数

使用 Phoenix Elixir 渲染分配以包含部分

未为结构实现协议可枚举。如何将结构转换为可枚举?

使用 Webpack 将语义 UI 添加到 Phoenix v1.4.3

收到错误:尝试创建/迁移/运行时在路径中找不到“nmake”

C#如何将枚举类(enum)型转换成字符(string)类型