如何使用"ecto".多删除`并避免查询get_by返回nil时出错



我的原始代码如下:

from(p in Mirror.Imports.Picture,
where: p.picture_name in ^picture_name_list
)
|> Repo.delete_all()
case Repo.get_by(Mirror.Imports.Product, num_id: num_id) do
nil -> #
:ok
value ->
Repo.delete(value)
:ok
end

我想使用Multi,并将其重写如下:

Ecto.Multi.new()
|> Ecto.Multi.delete_all(:delete_all,from(p in Mirror.Imports.Picture,
where: p.picture_name in ^picture_name_list))
|> Ecto.Multi.delete(:delete,  Repo.get_by(Mirror.Imports.Product, num_id: num_id))

但是新版本会错误地得到Repo.get_by返回nil吗?

错误消息如下:

== Compilation error in file mirror_a.exs ==
** (FunctionClauseError) no function clause matching in Ecto.Multi.delete/4    

The following arguments were given to Ecto.Multi.delete/4:

# 1
%Ecto.Multi{operations: [delete_all: {:delete_all, #Ecto.Query<from p0 in Mirror.Imports.Picture, where: p0.picture_name in ^["07258eb714o1cn01d___2367584017", "07269cdf84o1cn016___2367584017"]>, []}], names: MapSet.new([:delete_all])}

# 2
:delete

# 3
nil

# 4
[]

Attempted function clauses (showing 3 out of 3):

def delete(multi, name, %Ecto.Changeset{} = changeset, opts)
def delete(multi, name, %_{} = struct, opts) 
def delete(multi, name, fun, opts) when is_function(fun, 1)

(ecto 3.9.1) lib/ecto/multi.ex:388: Ecto.Multi.delete/4
(mirror 0.1.0) lib/mirror/imports.ex:497: Mirror.Imports.import_product/3
(elixir 1.14.1) lib/enum.ex:1658: Enum."-map/2-lists^map/1-0-"/2
(mirror 0.1.0) lib/mirror/imports.ex:467: Mirror.Imports.extract_csv/1
mirror_a.exs:14: (file)
(elixir 1.14.1) lib/kernel/parallel_compiler.ex:347: anonymous fn/5 in Kernel.ParallelCompiler.spawn_workers/7
** (CompileError)  compile error
(iex 1.14.1) lib/iex/helpers.ex:204: IEx.Helpers.c/2

Repo.get_by(Mirror.Imports.Product, num_id: num_id)返回nil时如何避免错误?

您的Ecto.Multi.delete/4调用失败,因为它需要Ecto.Schema.t()结构或变更集。您可以将delete_all/4与查询一起使用。在这种情况下,nil示例将是一个返回零行的查询,这很好。

Ecto.Multi.new()
- |> Ecto.Multi.delete(:product, Repo.get_by(Mirror.Imports.Product, num_id: num_id))
+ |> Ecto.Multi.delete_all(:product, from(p in Mirror.Imports.Product, where: p.num_id == ^num_id))

还要记住,Ecto.Multi是可组合的,您可以有条件地添加操作,例如:

Ecto.Multi.new()
|> Ecto.Multi.delete_all(:foo, foo_query)
|> Ecto.Multi.delete_all(:bar, bar_query)
|> maybe_delete_record(id)
# ...
def maybe_delete_record(multi, id) do
if record = Repo.get_by(Mirror.Imports.Product, num_id: num_id) do
Ecto.Multi.delete_all(multi, :baz, record)
else
multi
end
end

最新更新