Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/elixir/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Elixir 使用EXTO正确设置检查约束_Elixir_Ecto - Fatal编程技术网

Elixir 使用EXTO正确设置检查约束

Elixir 使用EXTO正确设置检查约束,elixir,ecto,Elixir,Ecto,我的模型中有这个check_约束 def changeset(struct, params \\ %{}) do struct |> cast(params, @all_fields) |> validate_required(@required_fields) |> check_constraint(:stars, name: :stars_range, message: "stars must be between 1 and 5")

我的模型中有这个check_约束

  def changeset(struct, params \\ %{}) do
    struct
    |> cast(params, @all_fields)
    |> validate_required(@required_fields)
    |> check_constraint(:stars, name: :stars_range, message: "stars must be between 1 and 5")
  end
已成功迁移创建约束

create constraint("reviews", "stars_range", check: "stars>=1 and stars<=5")
引自:

(…)现在,当调用Repo.insert/2或Repo.update/2时,如果价格不是正数,它将转换为一个错误,并由存储库返回{:error,changeset}。请注意,只有在命中数据库之后才会发生错误,因此在所有其他验证通过之前,该错误将不可见

这意味着只有当查询命中数据库时才会发生
check\u约束。因此,当您在实际调用数据库之前检查验证时,您的
变更集.valid?
将返回
true
。您创建的约束是在数据库中创建的,所以在调用它之前,Exto实际上无法知道该约束实际检查了什么。通常,此类约束用于更复杂的检查,或者如果数据库中已经定义了约束(可能是因为您从其他系统迁移了数据库?)。如果希望看到约束的作用,只需在测试中编写:

attrs=%{review_map|stars:7}
变更集=审查。变更集(属性)
{:错误,变更集}=Repo.insert(变更集)
反驳changeset.valid?
如果在调用数据库之前需要
Changeset
检查某些条件,则应使用
validate\u inclusion/4
validate\u subset/4
等函数。您甚至可以使用
validate\u change/4
编写自己的检查程序(如果需要更多关于如何执行的说明,请告诉我)。如果您使用这些验证器,那么您的变更集将在调用数据库之前工作。

如果我在为插入创建变更集时添加一些输出:

defmodule Foo do
  alias Foo.Review
  require Logger

  @repo Foo.Repo

  def list_reviews do
    @repo.all(Review)
  end

  def insert_review(attrs) do
    changeset = Review.changeset(%Review{}, attrs)

    ##   HERE ###
    Logger.debug("changeset.valid? => #{changeset.valid?}")

    @repo.insert(changeset)
  end

  def delete_book(%Book{}=book) do
    @repo.delete(book)
  end

end
以下是iex中的输出:

ex(3)> reviews = Foo.list_reviews                         
[debug] QUERY OK source="reviews" db=3.4ms
SELECT r0."id", r0."title", r0."contents", r0."stars", r0."inserted_at", r0."updated_at" FROM "reviews" AS r0 []
[]


## VALID DATA ###

iex(4)> Foo.insert_review(%{title: "book", contents: "good", stars: 4})  
[debug] changeset.valid? => true
[debug] QUERY OK db=2.3ms queue=2.0ms
INSERT INTO "reviews" ("contents","stars","title","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["good", 4, "book", ~N[2019-07-10 17:23:06], ~N[2019-07-10 17:23:06]]
{:ok,
 %Foo.Review{
   __meta__: #Ecto.Schema.Metadata<:loaded, "reviews">,
   contents: "good",
   id: 4,
   inserted_at: ~N[2019-07-10 17:23:06],
   stars: 4,
   title: "book",
   updated_at: ~N[2019-07-10 17:23:06]
 }}


## INVALID DATA ##

iex(5)> Foo.insert_review(%{title: "movie", contents: "shite", stars: 0})
[debug] changeset.valid? => true
[debug] QUERY ERROR db=6.1ms queue=1.5ms
INSERT INTO "reviews" ("contents","stars","title","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["shite", 0, "movie", ~N[2019-07-10 17:23:16], ~N[2019-07-10 17:23:16]]
{:error,
 #Ecto.Changeset<
   action: :insert,
   changes: %{contents: "shite", stars: 0, title: "movie"},
   errors: [
     stars: {"stars must be between 1 and 5 (inclusive)",
      [constraint: :check, constraint_name: "stars_range"]}
   ],
   data: #Foo.Review<>, 
   valid?: false
 >}
对于变更集中的错误,将
changeset.valid?
设置为
false
,然后返回
{:error,changeset}

当验证器失败时,输出会有所不同。当检查约束失败时。如果我将验证更改为:

  def changeset(%Foo.Review{}=review, attrs \\ %{}) do
    review
    |> cast(attrs, [:title, :contents, :stars])
    |> validate_required(:title)  ##<==== ADDED THIS VALIDATION
    |> check_constraint(
        :stars,
        name: :stars_range,
        message: "stars must be between 1 and 5 (inclusive)"
      )
  end
输出中的差异表明,只有在所有验证通过之后,Ecto才会尝试执行插入。当实际执行插入时,db会应用检查约束,这会导致插入失败,并且ecto会记录一个
查询错误


底线是:仅仅因为变更集有效并不意味着插入会成功。如果
changeset()
函数将
约束添加到数据库中,则在调用
@repo.insert(changeset)
实际执行插入之前,您无法知道插入变更集是否会成功

你试过这个吗?验证是否包含(:星号,1..5)?ref
验证包含内容
——很好!
   |> check_constraint(
        :stars,
        name: :stars_range,
        message: "stars must be between 1 and 5 (inclusive)"
      )
  def changeset(%Foo.Review{}=review, attrs \\ %{}) do
    review
    |> cast(attrs, [:title, :contents, :stars])
    |> validate_required(:title)  ##<==== ADDED THIS VALIDATION
    |> check_constraint(
        :stars,
        name: :stars_range,
        message: "stars must be between 1 and 5 (inclusive)"
      )
  end
iex(6)> Foo.insert_review(%{contents: "crowded", stars: 1})
[debug] changeset.valid? => false
{:error,
 #Ecto.Changeset<
   action: :insert,
   changes: %{contents: "crowded", stars: 1},
   errors: [title: {"can't be blank", [validation: :required]}],
   data: #Foo.Review<>,
   valid?: false
 >}
## INVALID DATA ##

iex(5)> Foo.insert_review(%{title: "movie", contents: "shite", stars: 0})
[debug] changeset.valid? => true
[debug] QUERY ERROR db=6.1ms queue=1.5ms
INSERT INTO "reviews" ("contents","stars","title","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5) RETURNING "id" ["shite", 0, "movie", ~N[2019-07-10 17:23:16], ~N[2019-07-10 17:23:16]]
{:error,
 #Ecto.Changeset<
   action: :insert,
   changes: %{contents: "shite", stars: 0, title: "movie"},
   errors: [
     stars: {"stars must be between 1 and 5 (inclusive)",
      [constraint: :check, constraint_name: "stars_range"]}
   ],
   data: #Foo.Review<>, 
   valid?: false
 >}
 [debug] QUERY ERROR db=6.1ms queue=1.5ms