【问题标题】:Ecto association to more than one schemes与多个计划的 Ecto 关联
【发布时间】:2016-01-16 03:13:54
【问题描述】:

假设我有这些架构:

defmodule Sample.Post do
  use Ecto.Schema

  schema "post" do
    field :title
    has_many :comments, Sample.Comment
  end
end

defmodule Sample.User do
  use Ecto.Schema

  schema "user" do
    field :name
    has_many :comments, Sample.Comment
  end
end

defmodule Sample.Comment do
  use Ecto.Schema

  schema "comment" do
    field :text
    belongs_to :post, Sample.Post
    belongs_to :user, Sample.User
  end
end

我的问题是如何使用Ecto.build_assoc 保存评论?

iex> post = Repo.get(Post, 13)
%Post{id: 13, title: "Foo"}
iex> comment = Ecto.build_assoc(post, :comments)
%Comment{id: nil, post_id: 13, user_id: nil}

到目前为止没问题,我需要做的就是使用相同的函数在我的Comment 结构中设置user_id,但是由于build_assoc 的返回值是Comment 结构,我不能使用一样的功能

iex> user = Repo.get(User, 1)
%User{id: 1, name: "Bar"}
iex> Ecto.build_assoc(user, :comment, comment)
** (UndefinedFunctionError) undefined function: Sample.Comment.delete/2
...

我有两个选择,但我觉得它们都不好看:

第一个是手动设置user_id

iex> comment = %{comment| user_id: user.id}
%Comment{id: nil, post_id: 13, user_id: 1}

第二个是将struct转换为map,然后......我什至不想去那里

有什么建议吗?

【问题讨论】:

    标签: associations elixir ecto


    【解决方案1】:

    为什么不希望将结构转换为映射?真的很简单。

    build_assoc 期望属性映射作为最后一个值。它在内部尝试删除密钥:__meta__。结构具有编译时间保证,它们将包含所有已定义的字段,因此您得到:

    ** (UndefinedFunctionError) undefined function: Sample.Comment.delete/2
    

    但你可以写:

    comment = Ecto.build_assoc(user, :comment, Map.from_struct comment)
    

    一切都会好起来的。

    【讨论】:

    • 我想我需要先删除__meta__,然后再发送给build_assoc
    【解决方案2】:

    只需将其与build_assoc一起传递

    iex> comment = Ecto.build_assoc(post, :comments, user_id: 1)
    %Comment{id: nil, post_id: 13, user_id: 1}
    

    查看here了解更多详情。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多