在Ecto中一起创建两个列的唯一约束

208*_*083 31 elixir ecto

如何在Ecto中的两列上创建唯一索引,这对应于:

CREATE TABLE someTable (
    col1 int NOT NULL,
    col2 int NOT NULL,
    primary key (col1, col2)
)
Run Code Online (Sandbox Code Playgroud)

The*_*uad 90

帕特里克的回答很少跟进

在模型上仅使用create unique_index最终会抛出异常而不是给出错误.

要获得错误,请在更改集上添加约束,但作为参数,您可以为unique_index创建索引名称.

所以在你的迁移文件中:

create unique_index(:your_table, [:col1, :col2], name: :your_index_name)
Run Code Online (Sandbox Code Playgroud)

然后在你的变更集中:

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

  • 绝对不是,当不符合约束时,您可以放置​​任何您想要的原子来获得全面的错误消息 (4认同)
  • 这应该标记为已接受的答案imo。@TheSquad,在这种情况下,:name_your_constraint是否需要为:col1或:col2?参考:https://hexdocs.pm/ecto/Ecto.Changeset.html#unique_constraint/3 (2认同)

Pat*_*ity 12

您可以使用多行创建唯一索引

create unique_index(:some_table, [:col1, :col2])
Run Code Online (Sandbox Code Playgroud)

我想如果你想要复合键,你需要使用execute/1手动运行SQL.不知道复合键与Ecto的工作情况有多好,我通常只是坚持每个表的标准序列号.

如果您应该使用复合键方法,我认为NOT NULL不需要约束.组合键应该已经强制列不为null.


Osk*_*kar 5

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
      ...
Run Code Online (Sandbox Code Playgroud)

架构:

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
    ...
Run Code Online (Sandbox Code Playgroud)

不过,在大多数情况下unique_index,这就是您想要的。