如何调试Ecto.Migration约束?

时间:2019-09-05 22:31:22

标签: ecto

在模式中使用Ecto.Schema.validate_format/4的正则表达式使用~r(/^\d{10}$)可以在模式中强制使用电话号码格式(例如“ 5551234567”),并且还决定向数据库添加约束,但是引发异常。

迁移:

defmodule ANV.Repo.Migrations.CreatePhoneNumbers do
  use Ecto.Migration

  def change do

    create table(:phone_numbers, primary_key: false) do

      add :id, :uuid, primary_key: true
      add :phone_number, :string

      timestamps()
    end

    create constraint(
      :phone_numbers,
      :phone_number_must_be_a_ten_digit_string,
      check: "phone_number ~ '^\d{10}$'"

      # This variant doesn't work either
      # check: "phone_number ~ $$^\d{10}\Z$$"
    )
  end
end

在下面的错误中,我找不到关于我做错什么的提示,并且按照下面的建议添加Ecto.Changeset.check_constraint/3也不会显示任何变更集错误,但是更新仍然会失败。

iex(2)> Repo.preload(admin, :phone_numbers) \
...(2)> |> Ecto.Changeset.change() \
...(2)> |> Ecto.Changeset.put_assoc(:phone_numbers, 
[%{phone_number: "5551234567"}]) \
...(2)> |> Repo.update()

[debug] QUERY OK source="phone_numbers" db=1.0ms queue=1.5ms
SELECT p0."id", p0."phone_number", p0."user_id", p0."inserted_at", p0."updated_at", p0."user_id" FROM "phone_number
s" AS p0 WHERE (p0."user_id" = $1) ORDER BY p0."user_id" [<<151, 69, 143, 150, 60, 216, 64, 125, 152, 42, 217, 7, 2
15, 117, 58, 30>>]
[debug] QUERY OK db=0.2ms
begin []
[debug] QUERY ERROR db=4.7ms
INSERT INTO "phone_numbers" ("phone_number","user_id","inserted_at","updated_at","id") VALUES ($1,$2,$3,$4,$5) ["55
51234567", <<151, 69, 143, 150, 60, 216, 64, 125, 152, 42, 217, 7, 215, 117, 58, 30>>, ~N[2019-09-05 21:39:43], ~N[
2019-09-05 21:39:43], <<217, 77, 187, 38, 201, 82, 78, 117, 156, 144, 64, 248, 249, 55, 227, 70>>]
[debug] QUERY OK db=0.3ms
rollback []
** (Ecto.ConstraintError) constraint error when attempting to insert struct:

    * phone_number_must_be_a_ten_digit_string (check_constraint)

If you would like to stop this constraint violation from raising an
exception and instead add it as an error to your changeset, please
call `check_constraint/3` on your changeset with the constraint
`:name` as an option.

The changeset has not defined any constraint.

    (ecto) lib/ecto/repo/schema.ex:687: anonymous fn/4 in Ecto.Repo.Schema.constraints_to_errors/3
    (elixir) lib/enum.ex:1336: Enum."-map/2-lists^map/1-0-"/2 
    (ecto) lib/ecto/repo/schema.ex:672: Ecto.Repo.Schema.constraints_to_errors/3
    (ecto) lib/ecto/repo/schema.ex:274: anonymous fn/15 in Ecto.Repo.Schema.do_insert/4
    (ecto) lib/ecto/association.ex:662: Ecto.Association.Has.on_repo_change/5
    (ecto) lib/ecto/association.ex:432: anonymous fn/8 in Ecto.Association.on_repo_change/7
    (elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto) lib/ecto/association.ex:428: Ecto.Association.on_repo_change/7
    (elixir) lib/enum.ex:1948: Enum."-reduce/3-lists^foldl/2-0-"/3
    (ecto) lib/ecto/association.ex:392: Ecto.Association.on_repo_change/4
    (ecto) lib/ecto/repo/schema.ex:837: Ecto.Repo.Schema.process_children/5
    (ecto) lib/ecto/repo/schema.ex:914: anonymous fn/3 in Ecto.Repo.Schema.wrap_in_transaction/6
    (ecto_sql) lib/ecto/adapters/sql.ex:890: anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4
    (db_connection) lib/db_connection.ex:1415: DBConnection.run_transaction/4

还重新配置了PostgreSQL日志记录(根据19.8. Error Reporting and Logging)以记录所有内容,但唯一相关的行也无济于事(或者我看不到明显的东西):

2019-09-05 22:26:33.060 UTC [15340] ERROR:  new row for relation "phone_numbers" violates check constraint "phone_number_must_be_a_ten_digit_string"
2019-09-05 22:26:33.060 UTC [15340] DETAIL:  Failing row contains (e4ce295a-9a7b-4a38-8e24-6f7191f711ce, 5551234567, 98b5b906-16f3-4ea0-875b-f8d4539efe06, 2019-09-05 22:26:33, 2019-09-05 22:26:33).
2019-09-05 22:26:33.060 UTC [15340] STATEMENT:  INSERT INTO "phone_numbers" ("phone_number","user_id","inserted_at","updated_at","id") VALUES ($1,$2,$3,$4,$5)

1 个答案:

答案 0 :(得分:1)

反斜杠需要转义。应该是

check: "phone_number ~ '^ \\ d{10}$'"


从初始迁移开始:

    create constraint(
      :phone_numbers,
      :phone_number_must_be_a_ten_digit_string,
      check: "phone_number ~ '^\d{10}$'"

相同的正则表达式,但直接在psql中输入:

ALTER TABLE phone_numbers 
  ADD CONSTRAINT phone_number_must_be_a_ten_digit_string2
  CHECK (phone_number ~ '^\d{10}$');

并排比较(使用\d+ phone_numbers中的psql

Check constraints:
    "phone_number_must_be_a_ten_digit_string" CHECK (phone_number::text ~ '^^?{10}$'::text)
    "phone_number_must_be_a_ten_digit_string2" CHECK (phone_number::text ~ '^\d{10}$'::text)