首页 > 解决方案 > Ecto(Phoenix)中的外键数组

问题描述

我是网络开发的初学者,所以请原谅我缺乏知识。

我有一个Teacher和一个StudentEcto 模式。它们应该Class通过遵循以下规则调用的另一个模式链接:

  1. 每个班只有一个老师,有很多学生。

  2. 每个老师都可以参加许多班级

  3. 每个学生都可以成为许多班级的一部分。

这是我到目前为止构建的架构:

# Part of student.ex
schema "students" do
    field :active, :boolean, default: false
    field :birthday, :date
    field :email, :string, unique: true
    field :firstname, :string
    field :lastname, :string
    field :phone, :string, unique: true
    belongs_to :classes, Class, foreign_key: :class_id
    many_to_many :teachers, Users.Teacher, join_through: "classes"

    timestamps()
  end
# Part of teacher.ex
schema "teachers" do
    field :active, :boolean, default: false
    field :birthday, :date
    field :email, :string, unique: true
    field :firstname, :string
    field :lastname, :string
    field :phone, :string, unique: true
    belongs_to :classes, Class, foreign_key: :class_id
    many_to_many :students, Users.Student, join_through: "classes"
    timestamps()
  end
# Part of class.ex
schema "classes" do
    field :end_date, :date
    field :time, :time
    field :level, :string
    field :start_date, :date
    field :title, :string
    has_many :students, Users.Student
    has_one :teacher, Users.Teacher
    embeds_many :sessions, Session
    timestamps()
  end

这里看起来还不错。但问题是,如何在迁移文件中指定“学生 ID 数组”?以下是迁移功能:

# Part of students migration file. It's the same for teachers.
def change do
    create table(:students) do
      add :firstname, :string, null: false, size: 32
      add :lastname, :string, null: false, size: 32
      add :phone, :string, null: false, size: 16
      add :email, :string, size: 32
      add :birthday, :date
      add :active, :boolean, default: false, null: false

      timestamps()
    end

    create(unique_index(:students, [:phone]))
  end

这是我现在真正陷入困境的地方:

def change do
    create table(:classes) do
      add :title, :string, null: false
      add :level, :string
      add :hours, :string, null: false
      add :start_date, :date
      add :end_date, :date
      add :teacher_id, references(:teachers), primary_key: true
      # HERE! How do I create a column for an array of student_id foreign keys?
      timestamps()
    end

    create(index(:classes, [:teacher_id]))

  end

提前致谢。

标签: elixirphoenix-frameworkecto

解决方案


正如文档中所述Ecto.Schema.belongs_to/3

您应该belongs_to在包含外键的表中使用。想象一段company <-> employee关系。如果在基础数据库表中employee包含,我们说属于。事实上,当您调用此宏时,会在架构中自动为您定义一个名为外键的字段。company_idemployeecompany

相反,既不Ecto.Schema.has_one/3也不Ecto.Schema.has_many/3暗示各自领域的存在。一切都在此链接的另一端完成。

也就是说,

  • students架构应该有class_id字段(已经在那里)
  • classes可能应该有teacher_id(假设老师可能有几个班级。)要做到这一点,请更改teachershas_many :classes而不是belongs_to :class 更改classesbelongs_to :teacher而不是has_one :teacher

无论您是否希望学生属于多个班级,架构都是不正确的。class_id每个记录中外键的存在students意味着每个学生都有这个特定的类相关联。你应该删除

belongs_to :classes, Class, foreign_key: :class_id

students,因为它首先将一个学生固定在一个班级。然后你必须引入classes_to_students连接模式,如此处所述Ecto.Schema.many_to_many/3


推荐阅读