如何在 Ecto 中的两列上创建唯一索引,这对应于:
CREATE TABLE someTable (
col1 int NOT NULL,
col2 int NOT NULL,
primary key (col1, col2)
)
?
帕特里克的回答的一些后续
仅在模型上使用 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
您可以使用
跨多行创建唯一索引create unique_index(:some_table, [:col1, :col2])
execute/1
手动运行 SQL。虽然不确定复合键与 Ecto 的配合效果如何,但我通常只坚持使用每个表的标准序列 ID。
如果您应该采用复合键方法,我认为
NOT NULL
约束是不必要的。组合键应该已经强制列不为空。
unique_index/3
不会创建复合主键,如问题示例中所示。它确实创建了一个独特的约束。
如果您确实想创建复合主键(注意:在使用 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
...
在大多数情况下,就是您想要的。
constraint 与唯一的 index 不同(至少不是在 PostGres 的所有版本中——这方面似乎有一些变化)。在 Ecto 中,目前添加非索引约束的唯一方法似乎是在迁移中使用 execute/1
,例如
defmodule YourMigration do
use Ecto.Migration
def up do
execute("""
ALTER TABLE pre.yourtable
ADD CONSTRAINT something UNIQUE (something)
""")
end
def down do
execute("""
ALTER TABLE pre.yourtable
DROP CONSTRAINT something
""")
end
end