首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何调试Ecto.Migration约束?

如何调试Ecto.Migration约束?
EN

Stack Overflow用户
提问于 2019-09-06 06:31:23
回答 1查看 43关注 0票数 0

在模式中强制电话号码的格式(比如"5551234567")在~r(/^\d{10}$)正则表达式中使用Ecto.Schema.validate_format/4可以很好地工作,并且决定也向数据库添加一个约束,但是它抛出了一个异常。

迁移:

代码语言:javascript
复制
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也不会显示任何变更集错误,但更新仍然会失败。

代码语言:javascript
复制
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),以记录所有内容,但唯一相关的行也没有帮助(或者我没有看到明显的东西):

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

回答 1

Stack Overflow用户

发布于 2019-09-06 23:19:08

反斜杠需要转义。它应该是

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

从初始迁移开始:

代码语言:javascript
复制
    create constraint(
      :phone_numbers,
      :phone_number_must_be_a_ten_digit_string,
      check: "phone_number ~ '^\d{10}$'"

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

代码语言:javascript
复制
ALTER TABLE phone_numbers 
  ADD CONSTRAINT phone_number_must_be_a_ten_digit_string2
  CHECK (phone_number ~ '^\d{10}$');

并排比较(在psql中使用\d+ phone_numbers ):

代码语言:javascript
复制
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)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/57813697

复制
相关文章

相似问题

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