Создание уникального ограничения на два столбца вместе в Ecto

Как создать уникальный индекс в двух столбцах в Ecto, который соответствовал бы этому:

CREATE TABLE someTable (
    col1 int NOT NULL,
    col2 int NOT NULL,
    primary key (col1, col2)
)

?

Ответы

Ответ 1

Вы можете создать уникальный индекс в нескольких строках с помощью

create unique_index(:some_table, [:col1, :col2])

Я полагаю, что если вы хотите иметь составные клавиши, вам нужно использовать execute/1 для запуска SQL вручную. Не уверен, насколько хорошо составные клавиши работают с Ecto, хотя я обычно придерживаюсь стандартного серийного идентификатора в таблице.

Если вы хотите использовать подход с комбинированным ключом, я думаю, что ограничения NOT NULL не нужны. Компонентный ключ должен уже обеспечивать, чтобы столбцы не были нулевыми.

Ответ 2

Небольшое продолжение ответа Патрика

Использование только create unique_index в вашей модели в конечном итоге приведет к исключению вместо того, чтобы дать вам ошибку.

Чтобы получить ошибку, добавьте ограничение на свой набор изменений, но в качестве пареметра вы можете указать имя индекса, созданное unique_index.

Итак, в файле миграции:

create unique_index(:your_table, [:col1, :col2], name: :your_index_name)

Затем в вашем наборе изменений:

def changeset(model, param \\ :empty) do
  model
  |> cast(params, @required_fields, @optional_fields)
  |> unique_constraint(:name_your_constraint, name: :your_index_name)
end

Ответ 3

unique_index будет не создавать составной первичный ключ, как показано в примере вопроса. Это создает уникальное ограничение.

Если вы хотите создать составной первичный ключ (обратите внимание: не рекомендуется при работе с Ecto), здесь больше информации:

Миграция:

defmodule HelloPhoenix.Repo.Migrations.CreatePlayer do
  use Ecto.Migration

  def change do
    create table(:players, primary_key: false) do
      add :first_name, :string, primary_key: true
      add :last_name, :string, primary_key: true
      add :position, :string
      add :number, :integer
      ...

Схема:

defmodule HelloPhoenix.Player do
  use Ecto.Schema

  @primary_key false
  schema "players" do
    field :first_name, :string, primary_key: true
    field :last_name, :string, primary_key: true
    field :position, :string
    field :number, :integer
    ...

В большинстве случаев unique_index - это то, что вы хотите.