Массив внешних ключей в Экто (Феникс) - PullRequest
0 голосов
/ 22 апреля 2020

Я новичок в веб-разработке, так что извините за недостаток знаний.

У меня есть схемы Teacher и Student Ecto. Предполагается, что они связаны между собой другой схемой, называемой 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

Здесь все выглядит хорошо. Но проблема в том, как мне указать «массив идентификаторов студентов» в моем файле миграции? Вот функции миграции:

# 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

Заранее спасибо.

1 Ответ

1 голос
/ 22 апреля 2020

Как указано в документах для Ecto.Schema.belongs_to/3

Вы должны использовать belongs_to в таблице, содержащей внешний ключ. Представьте себе company <-> employee отношения. Если employee содержит company_id в базовой таблице базы данных, мы говорим, что employee принадлежит company. Фактически, когда вы вызываете этот макрос, в схеме автоматически определяется поле с именем внешнего ключа.

Напротив, ни Ecto.Schema.has_one/3, ни Ecto.Schema.has_many/3 подразумевает существование соответствующего поля. Все делается на другом конце этой ссылки.

При этом

  • students схема должна иметь поле class_id (уже там)
  • classes вероятно должно иметь teacher_id (при условии, что у учителя может быть несколько классов.) Для этого измените teachers на has_many :classes вместо belongs_to :class и , измените classes на belongs_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.

...