首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Ecto:用foreign_key_constraint raise Postgrex.Error插入变更集

Ecto:用foreign_key_constraint raise Postgrex.Error插入变更集
EN

Stack Overflow用户
提问于 2018-01-24 15:22:54
回答 1查看 1.4K关注 0票数 1

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

我定义了两个模式来表示ownerhousehouse模式有一个FK (belongs_to) owner。我为house定义了一个模式和一个变更集,如下所示:

代码语言:javascript
复制
 @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

代码语言:javascript
复制
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的内容,就会得到以下结果:

代码语言:javascript
复制
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模式如下所示:

代码语言:javascript
复制
    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
EN

回答 1

Stack Overflow用户

发布于 2018-01-24 16:05:37

这太奇怪了。我有一个非常类似的方案,它的工作与预期的相同的限制。

代码语言:javascript
复制
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)时:

代码语言:javascript
复制
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>}

但是,前面也出现了相同的错误,但我认为在使用此任务重置数据库时修复了该错误:

代码语言:javascript
复制
mix ecto.drop
mix ecto.create
mix ecto.migrate 
mix run priv/repo/seeds.exs

该任务重新创建数据库并运行迁移。

凭据SQL Schema:

代码语言:javascript
复制
                                      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

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48425959

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档