嵌套孩子的Ecto祖父母关键字

时间:2016-09-17 04:50:30

标签: elixir phoenix-framework ecto

organization有很多users

schema "organizations" do
  field :name, :string
  has_many :users, TestApp.User
end

user有许多subordinates

schema "users" do
  field :name, :string
  belongs_to :organization, TestApp.Organization
  belongs_to :manager, TestApp.User,
    foreign_key: :manager_id
  has_many :subordinates, TestApp.User,
    foreign_key: :manager_id
end

如何以下列方式创建下属时,如何确保下属具有organization_id值?

  test "create Org and User and Subordinate in one step" do
    subordinate =
      %User{}
      |> User.changeset(%{name: "A Subordinate"})

    manager =
      %User{}
      |> User.changeset(%{name: "A Manager"})
      |> Changeset.put_assoc(:subordinates, [subordinate])

    organization =
      %Organization{}
      |> Organization.changeset(%{name: "An Organization"})
      |> Changeset.put_assoc(:users, [manager])

    %{users: [ %{subordinates: [subordinate]} = manager]} = organization = Repo.insert!(organization)

    # Passes
    assert manager.organization_id == organization.id
    # Fails
    assert subordinate.organization_id == organization.id
  end

1 个答案:

答案 0 :(得分:0)

<强>选项1
调用Repo.insert!分别在每个变更集上

subordinate =
  %User{}
  |> User.changeset(%{name: "A Subordinate"})
  |> Repo.insert!

manager =
  %User{}
  |> User.changeset(%{name: "A Manager"})
  |> Changeset.put_assoc(:subordinates, [subordinate])
  |> Repo.insert!

创建辅助函数,返回与其下属合并的管理者列表

defp managers_with_subordinates(managers) do
  Enum.reduce(managers, [], &(&2 ++ [&1] ++ &1.subordinates))
end

然后将结果传递给put_assoc

users = managers_with_subordinates([manager])

organization =
  %Organization{}
  |> Organization.changeset(%{name: "An Organization"})
  |> Changeset.put_assoc(:users, users)

并将模式匹配更改为

%{users: [user1, user2]} = organization = %Organization{} |> Organization.changeset |> put_assoc(:users, x) |> Repo.insert!

assert user1.organization_id == organization.id
assert user2.organization_id == organization.id
assert user2.manager_id == user1.id

<强>选项2

subordinate =
  %User{}
  |> User.changeset(%{name: "A Subordinate"})
  |> prepare_changes( fn(changeset) ->
    manager = changeset.repo.get(User, changeset.changes.manager_id)
    changeset |> cast(%{organization_id: manager.organization_id}, [:organization_id])
  )