【问题标题】:Elixir Ecto: How to validate foreign key constraint?Elixir Ecto:如何验证外键约束?
【发布时间】:2015-08-25 13:21:26
【问题描述】:

我正在使用 Elixir 和 Phoenix Web 框架,但现在我一直在尝试验证外键约束。所以,给定一个模型Post许多cmets,我写了Comment 模型如下:

defmodule MyApp.Comment do
  use MyAPp.Web, :model

  schema "comments" do
    field :body, :text
    belongs_to :post, MyApp.Post

    timestamps
  end

  @required_fields ~w(body post_id)
  @optional_fields ~w()

  def changeset(model, params \\ :empty) do
    model
    |> cast(params, @required_fields, @optional_fields)
    |> foreign_key_constraint(:post_id)
  end
end

及其单元测试:

defmodule MyApp.CommentTest do
  # [...]
  test "changeset with non existent post" do
    attrs = %{
      body: "A comment."
      post_id: -1 # some non-existent id?
    }
    refute Comment.changeset(%Comment{}, attrs).valid?
    assert {:post_id, "does not exist"} in errors_on(%Comment{}, %{})
  end
end

根据http://hexdocs.pm/ecto/Ecto.Changeset.html#foreign_key_constraint/3

外键约束依靠数据库来检查 关联模型是否存在。这有助于保证 仅当父项存在于数据库中时才会创建子项 也是。

我希望我编写的代码能够正常工作,但它只检查存在(如@required_fields ~w(body post_id) 中所定义)。我不排除我做错了什么或误解了文档中的声明。

有没有人偶然发现过这个?

更新: 为了完整起见,这里是迁移:

def change do
  create table(:comments) do
    add :body, :text
    add :post_id, references(:posts)

    timestamps
  end

  create index(:comments, [:post_id])
end

【问题讨论】:

  • 能否请您也提供您的迁移?
  • @Gazler 编辑了我的问题,添加了迁移。

标签: elixir phoenix-framework ecto


【解决方案1】:

由于依赖于数据库,所以需要在迁移中添加引用,进行实际的数据库操作。您必须调用 Repo.insert/1Repo.update/1 提供您的变更集,然后它将返回 {:error, changeset}

请记住,Elixir 和 Ecto 中都没有对象。因此changeset.valid? 永远无法执行数据库操作,它只是反映要执行的一组更改的数据,并且当您执行插入或更新等操作时,此数据的状态会发生变化。

最后一点,errors_on/2 总是会返回一个新的变更集,而不是你目前使用的那个。您的最后一行应该是:

assert {:post_id, "does not exist"} in changeset.errors

【讨论】:

  • 非常感谢您的完整回答。在这种情况下,问题出在其他地方:在对迁移进行一些修改后,我没有重新创建测试数据库。所以架构是没有限制的。另外,我做了你建议的改变。再次感谢你! :-)
【解决方案2】:

“依赖数据库”表示您的数据库模型中需要有 FOREIGN KEY CONSTRAINT。

在你的迁移中,你应该有这样的东西:

create table(:comments) do
  add :post_id, references(:posts)
end

在父表和子表之间强制执行 FOREIGN KEY CONSTRAINT CHECK。

【讨论】:

  • 确实,我在迁移中做到了这一点。我更新了我的问题并添加了迁移代码。
猜你喜欢
  • 2016-10-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-06
  • 1970-01-01
  • 2018-11-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多