Ecto:使用foreign_key_constraint插入changeset引发Postgrex.Error

时间:2018-01-24 15:22:54

标签: postgresql elixir ecto

我正在使用Ecto(2.2.8)来处理现有的PostgreSQL数据库。

我定义了两个模式来表示ownerhousehouse架构有一个FK(belongs_toowner。我为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的{​​{1}}记录,我希望以下代码返回元组id

10

但是,我收到了 Postgrex.Error

House.changeset(%House{}, %{name: "Whatever", owner_id: 10}) |> Repo.insert

如果我在致电** (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,我可以按照文档的建议进行模式匹配吗?

更新

我没有使用Ecto的迁移。已创建数据库表,并且迁移由不同的项目处理。 SQL Schema看起来像这样:

{:error, changeset}

1 个答案:

答案 0 :(得分:0)

这很奇怪。我有一个非常类似的方案,它按预期工作,具有相同的约束。

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架构:

                                      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

Project DB Dependencies:

Phoenix-Ecto - &gt; 3.2 Postgresx&gt; = 0.0.0