在模式中使用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)
答案 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)