我使用Ecto (2.2.8)来处理现有的PostgreSQL数据库。
我定义了两个模式来表示owner和house。house模式有一个FK (belongs_to) owner。我为house定义了一个模式和一个变更集,如下所示:
@primary_key {:id, :id, autogenerate: true}
schema "house" do
belongs_to :owner, Owner, foreign_key: :owner_id
field :name, :string
end
def changeset(house, params \\ %{}) do
house
|> cast(params, [:name, :owner_id])
|> validate_required([:owner_id])
|> foreign_key_constraint(:owner_id)
end问题
当数据库中没有带有{:error, changeset} owner记录的id 10时,我期望下面的代码返回元组10:
House.changeset(%House{}, %{name: "Whatever", owner_id: 10}) |> Repo.insert但是,我得到了一个Postgrex.Error:
** (Postgrex.Error) ERROR 23503 (foreign_key_violation): insert or update on table "house" violates foreign key constraint "house_owner_id_fkey"。
如果在调用changeset.constraints之前检查Repo.insert的内容,就会得到以下结果:
House.changeset(%House{}, %{name: "Whatever", owner_id: 10})
|> Map.get(:constraints)
[
%{
constraint: "house_owner_id_fkey",
error: {"does not exist", []},
field: :owner_id,
match: :exact,
type: :foreign_key
}
]因此,在使用foreign_key_constraint时,我不应该得到一个可以按照文档的建议进行模式匹配的元组{:error, changeset}吗?
更新
我不想用埃克托的迁徙。数据库表已经创建,迁移由不同的项目处理。SQL模式如下所示:
Column | Type | Modifiers
---------------+---------+-------------------------------------------------------
id | integer | not null default nextval('house_id_seq'::regclass)
owner_id | integer | not null
Indexes:
"house_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
"house_owner_id_fkey" FOREIGN KEY (owner_id) REFERENCES owner(id) DEFERRABLE INITIALLY DEFERRED发布于 2018-01-24 16:05:37
这太奇怪了。我有一个非常类似的方案,它的工作与预期的相同的限制。
defmodule Hello.Accounts.Credential do
use Ecto.Schema
import Ecto.Changeset
alias Hello.Accounts.{Credential, User}
schema "credentials" do
field :email, :string
belongs_to :user, User, foreign_key: user_id
timestamps()
end
@doc false
def changeset(%Credential{} = credential, attrs) do
credential
|> cast(attrs, [:email, :user_id])
|> validate_required([:email, :user_id])
|> unique_constraint(:email)
|> foreign_key_constraint(:user_id)
end
end当我插入无效记录(不存在user_id)时:
Credential.changeset(%Credential{}, %{email: "test@c.c", user_id: 2}) |> Repo.insert
{:error,
#Ecto.Changeset<action: :insert, changes: %{email: "test@c.c", user_id: 2},
errors: [user_id: {"does not exist", []}], data: #Hello.Accounts.Credential<>,
valid?: false>}但是,前面也出现了相同的错误,但我认为在使用此任务重置数据库时修复了该错误:
mix ecto.drop
mix ecto.create
mix ecto.migrate
mix run priv/repo/seeds.exs该任务重新创建数据库并运行迁移。
凭据SQL Schema:
Table "public.credentials"
Column | Type | Modifiers
-------------+-----------------------------+----------------------------------------------------------
id | bigint | not null default nextval('credentials_id_seq'::regclass)
email | character varying(255) |
user_id | bigint | not null
inserted_at | timestamp without time zone | not null
updated_at | timestamp without time zone | not null
Indexes:
"credentials_pkey" PRIMARY KEY, btree (id)
"credentials_email_index" UNIQUE, btree (email)
"credentials_user_id_index" btree (user_id)
Foreign-key constraints:
"credentials_user_id_fkey" FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE项目DB依赖:
凤凰-Ecto -> 3.2 Postgresx >= 0.0.0
https://stackoverflow.com/questions/48425959
复制相似问题