[英]Elixir: comparison with nil is forbidden as it is unsafe
我对Elixir
很陌生。 我正面临这个错误:
2022-07-06 13:52:53.022 [info] pid=<0.31.0> Application mt_consumer exited: MTConsumer.Application.start(:normal, []) returned an error: shutdown: failed to start child: MTConsumer
** (EXIT) an exception was raised:
** (ArgumentError) comparison with nil is forbidden as it is unsafe. If you want to check if a value is nil, use is_nil/1 instead
(ecto) lib/ecto/query/builder.ex:551: Ecto.Query.Builder.not_nil!/1
(mt_model) lib/mt_model/location.ex:36: MTModel.Location.raw_id_by_name_tenant/2
(mt_consumer) lib/mt_consumer.ex:66: MTConsumer.handle_job/1
(mt_consumer) lib/mt_consumer.ex:38: MTConsumer.loop/1
(stdlib) supervisor.erl:365: :supervisor.do_start_child/2
(stdlib) supervisor.erl:348: :supervisor.start_children/3
(stdlib) supervisor.erl:314: :supervisor.init_children/2
(stdlib) gen_server.erl:328: :gen_server.init_it/6
现在这是我的代码:
def id_by_name_tenant(name, tenant_id) do
id = raw_id_by_name_tenant(name, tenant_id)
case id do
nil -> raw_id_by_name_tenant(@default_name, nil)
_ -> id
end
end
defp raw_id_by_name_tenant(name, tenant_id) do
from(
l in MTModel.Location,
where: l.name == ^name and l.tenant_id == ^tenant_id,
limit: 1,
select: l.id
) |> MTModel.Repo.one([])
end
defp raw_id_by_name_tenant(name, _) do
from(
l in MTModel.Location,
where: l.name == ^name,
limit: 1,
select: l.id
) |> MTModel.Repo.one()
end
我在这里做错了什么? 该代码早些时候运行良好,但在重新部署后它开始产生问题。
您正在使用nil
参数调用函数raw_id_by_name_tenant/2
,然后使用此处的字段进行检查:
where: l.name == ^name and l.tenant_id == ^tenant_id,
这在 Ecto 中是被禁止的,如果你必须检查 nil 你必须使用is_nil/1
。
您可以使用dynamic/2
重构您的函数,而不是将 nil 传递给您的查询:
defp raw_id_by_name_tenant(name, tenant_id) do
from(
l in MTModel.Location,
where: ^with_name(name) and ^with_tenant_id(tenant_id),
limit: 1,
select: l.id
) |> MTModel.Repo.one([])
end
defp with_name(nil), do: true
defp with_name(name), do: dynamic([l], l.name == ^name)
defp with_tenant_id(nil), do: true
defp with_tenant_id(tenant_id), do: dynamic([l], l.tenant_id == ^tenant_id)
raw_id_by_name_tenant/2
的第二个子句永远不会匹配,因为第一个总是匹配。 例如,您可能忘记在第一个子句中防范nil
defp raw_id_by_name_tenant(name, tenant_id) when tenant_id != nil do
或将第二个子句向上移动并替换为
defp raw_id_by_name_tenant(name, nil) do
但我认为您可以通过使用Repo.get_by/2
来简化此代码,消除对私有函数的需求并使意图更清晰(如果您的 name/tenant_id 对是唯一的):
def id_by_name_tenant(name, tenant_id) do
query = select(MTModel.Location, [l], l.id)
case Repo.get_by(query, name: name, tenant_id: tenant_id) do
nil -> Repo.get_by(query, name: @default_name)
id -> id
end
end
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.