Ecto中的多对多关联预加载错误

时间:2019-06-08 15:10:11

标签: elixir phoenix-framework ecto

I am learning Ecto and was trying out many to many relationship.
I am using MySQL DB, 

方案是这样的

  

用户架构

  @primary_key {:id, :binary_id, autogenerate: true}
  schema "users" do
    field(:name, :string, required: true)
    field(:hashed_password, :string, required: true)
    field(:password, :string, virtual: true)
    timestamps()

    many_to_many(:methods, Bookie.Method.Model, join_through: "users_methods", on_replace: :delete)
  end

  

方法架构

  @primary_key {:id, :binary_id, autogenerate: true}
  schema "methods" do
    field(:function, :string, required: true)
    field(:method, :string, required: true)
    timestamps()

    many_to_many(:users, Bookie.User.Model, join_through: "users_methods", on_replace: :delete)
  end
  

这2个方案的关联-users_methods


  schema "users_methods" do
    belongs_to(:users, Bookie.User.Model, type: :binary_id)
    belongs_to(:methods, Bookie.Method.Model, type: :binary_id)
  end

这些是我的迁移

  create table(:users, primary_key: false) do
      add(:id, :uuid, primary_key: true)
      add(:name, :string, null: false)
      add(:hashed_password, :string, null: false)
      timestamps()
    end

   create(unique_index(:users, [:name]))

    create table(:methods, primary_key: false) do
      add(:id, :uuid, primary_key: true)
      add(:function, :string, null: false)
      add(:method, :string, null: false)
      timestamps()
    end

 create table(:users_methods, primary_key: false) do
      add(:user_id, references("users", type: :uuid, on_delete: :delete_all))
      add(:method_id, references("methods", type: :uuid, on_delete: :delete_all))
    end

    create(index(:users_methods, [:method_id]))
    create(index(:users_methods, [:user_id]))

    create(
      unique_index(:users_methods, [:user_id, :method_id], name: :user_id_method_id_unique_index)
    )

这是我的基本设置。现在,一旦我在查询/插入用户后尝试预加载方法,就会给我错误。

  user_map = %{name: "User 1", password: "password"}

  changeset =
    User.changeset(%User{}, user_map)
    |> Ecto.Changeset.put_change(
      :hashed_password,
      User.hashed_password(changeset.changes[:password])
    )

  user =
    Repo.insert!(changeset)
    |> Repo.preload(:methods)

错误


  [debug] QUERY OK db=2.6ms queue=0.1ms
begin []
[debug] QUERY OK db=3.5ms
INSERT INTO `users` (`hashed_password`,`name`,`inserted_at`,`updated_at`,`id`) VALUES (?,?,?,?,?) ["$2b$12$6W3zoeCnfLRV3N0fzv5t..LFnZly93G4IvfM5DfQSaEWPLtK0jV8q", "User 1", {{2019, 6, 8}, {14, 29, 25, 458464}}, {{2019, 6, 8}, {14, 29, 25, 458477}}, <<208, 210, 137, 42, 54, 3, 75, 211, 148, 173, 9, 174, 171, 125, 44, 225>>]
[debug] QUERY OK db=0.7ms
commit []
[debug] QUERY ERROR source="methods" db=29.5ms
SELECT m0.`id`, m0.`function`, m0.`method`, m0.`inserted_at`, m0.`updated_at`, u1.`id` FROM `methods` AS m0 INNER JOIN `users` AS u1 ON u1.`id` IN (?) INNER JOIN `users_methods` AS u2 ON u2.`model_id` = u1.`id` WHERE (u2.`model_id` = m0.`id`) ORDER BY u1.`id` [<<208, 210, 137, 42, 54, 3, 75, 211, 148, 173, 9, 174, 171, 125, 44, 225>>]
** (Mariaex.Error) (1054): Unknown column 'u2.model_id' in 'where clause'
    (ecto) lib/ecto/adapters/sql.ex:450: Ecto.Adapters.SQL.sql_call!/6
    (ecto) lib/ecto/adapters/sql.ex:420: Ecto.Adapters.SQL.do_execute/6
    (ecto) lib/ecto/repo/queryable.ex:133: Ecto.Repo.Queryable.execute/5
    (ecto) lib/ecto/repo/queryable.ex:37: Ecto.Repo.Queryable.all/4
    (elixir) lib/enum.ex:1327: Enum."-map/2-lists^map/1-0-"/2
  

(Mariaex.Error)(1054):“ where子句”中的未知列“ u2.model_id”

我没有超越:(

请帮助。

1 个答案:

答案 0 :(得分:1)

关联外键从模式名称的最后一部分开始变化。由于您的所有架构都命名为Foo.Bar.Model,因此它们都默认为model_id。您可以通过join_keys选项来指定关系。

例如:

many_to_many(:methods, Bookie.Method.Model, join_through: "users_methods", on_replace: :delete)

应为:

many_to_many(:methods, Bookie.Method.Model, join_through: "users_methods", join_keys: [user_id: :id, method_id: :id], on_replace: :delete)

并且:

many_to_many(:users, Bookie.User.Model, join_through: "users_methods", on_replace: :delete)

应该是:

many_to_many(:users, Bookie.User.Model, join_through: "users_methods", join_keys: [method_id: :id, user_id: :id], on_replace: :delete)

尽管我建议遵循Ecto的命名约定,但是一切都会变得更加简单。