Elixir/Ecto null FK 在插入多对多表时

问题描述

问题:多对多表的 FK 字段保持为空 我有一个简单的多对多表来连接用户表和雇主表:

用户表:

  schema "users" do
    field :email,:string
    field :first_name,:string
    field :hashed_password,:string,redact: true
    field :password,virtual: true
    field :password_confirmation,virtual: true
    field :is_active,:boolean,default: false
    field :last_name,:string
    field :middle_name,:string

    many_to_many :employers,Employer,join_through: UserEmployer

    timestamps()
  end

雇主表:

 schema "employers" do
    field :employer_name,:string

    many_to_many :users,User,join_through: UserEmployer

    timestamps()
  end

UsersEmployers 表:

  schema "users_employers" do
    belongs_to :users,User
    belongs_to :employers,Employer
    
    timestamps()
  end

要在 iex 中使用此关联,我将获取用户 (user1) 和雇主 (employer1) 并运行:

user1 
|> Repo.preload(:employers) 
|> User.changeset(%{}) 
|> Ecto.Changeset.put_assoc(:employers,[employer1]) 
|> Repo.update!

输出

17:01:23.896 [debug] QUERY OK db=0.8ms
INSERT INTO "users_employers" ("inserted_at","updated_at","id") VALUES ($1,$2,$3) [~N[2021-05-17 17:01:23],~N[2021-05-17 17:01:23],<<97,185,97,180,30,80,73,50,130,255,57,243,107,136,85,74>>]
17:01:23.898 [debug] QUERY OK db=2.3ms
commit []
%DB.Users.User{
  __Meta__: #Ecto.Schema.Metadata<:loaded,"users">,email: "mafia4lye@gmail.com",employers: [
    %DB.Employers.Employer{
      __Meta__: #Ecto.Schema.Metadata<:loaded,"employers">,employer_name: "Employer Number 1",id: "0ed08a40-7315-4c90-a2cf-7d66cb5b7b89",inserted_at: ~N[2021-05-17 16:31:41],updated_at: ~N[2021-05-17 16:31:41],users: #Ecto.Association.NotLoaded<association :users is not loaded>
    }
  ],first_name: "Vito",hashed_password: "not_hashed_yet",id: "9e0d7497-0fb5-48f6-a0ba-7c6af2f6daf7",inserted_at: ~N[2021-05-17 16:31:42],is_active: true,last_name: "Corleone",middle_name: "Mob",password: nil,password_confirmation: nil,updated_at: ~N[2021-05-17 16:31:42]
}

该行插入到 UsersEmployers 表中,但是 FK 的 user_id 和雇主 ID 为空。

解决方法

您应该在 belongs_to 关联中使用“单数”形式(而不是“复数”形式):

  schema "users_employers" do
    belongs_to :user,User
    belongs_to :employer,Employer
    
    timestamps()
  end