我有一个upsert要求,所以我需要调用postgres存储过程或使用公用表表达式.我还使用pgcrypto exgtension进行密码,并希望使用postgres函数(例如"crypt"来编码/解码密码).
但是我无法找到一种方法让Ecto部分或全部使用原始sql,它是否意味着ecto只支持elixir dsl并且当dsl不够时不允许shell-out到原始sql?
我发现我可以通过适配器查询(Rocket是应用程序的名称)
q = Ecto.Adapters.Postgres.query(Rocket.Repo,"select * from users limit 1",[])
Run Code Online (Sandbox Code Playgroud)
但不确定如何将其转化为模型.我是elixir的新手,似乎我应该可以使用Ecto.Model.Schem.schema/3但是失败了
Rocket.User.__schema__(:load,q.rows |> List.first,0)
** (FunctionClauseError) no function clause matching in Rocket.User.__schema__/3
Run Code Online (Sandbox Code Playgroud)
jam*_*svl 34
在Postgres的Ecto 2.0(beta)上,您可以使用Ecto.Adapters.SQL.query()(当前的文档,2.0-beta2文档)来执行任意SQL; 除了行本身(" rows")的列表之外,它恰好返回列名称列表(" columns").
在下面的例子中,我
(你可能想要运行query()版本(没有爆炸!)并检查{ok, res}.)
qry = "SELECT * FROM users"
res = Ecto.Adapters.SQL.query!(Repo, qry, []) # a
cols = Enum.map res.columns, &(String.to_atom(&1)) # b
roles = Enum.map res.rows, fn(row) ->
struct(MyApp.User, Enum.zip(cols, row)) # c
end
Run Code Online (Sandbox Code Playgroud)
小智 9
针对Ecto 2.0的修改解决方案:
在repo.ex:
def execute_and_load(sql, params, model) do
Ecto.Adapters.SQL.query!(__MODULE__, sql, params)
|> load_into(model)
end
defp load_into(response, model) do
Enum.map(response.rows, fn row ->
fields = Enum.reduce(Enum.zip(response.columns, row), %{}, fn({key, value}, map) ->
Map.put(map, key, value)
end)
Ecto.Schema.__load__(model, nil, nil, nil, fields,
&Ecto.Type.adapter_load(__adapter__, &1, &2))
end)
end
Run Code Online (Sandbox Code Playgroud)
用法:
Repo.execute_and_load("SELECT * FROM users WHERE id = $1", [1], User)
Run Code Online (Sandbox Code Playgroud)
现在Ecto 1.0已经出来了,这应该有一段时间了:
将以下功能添加到您的Repo模块:
def execute_and_load(sql, params, model) do
Ecto.Adapters.SQL.query!(__MODULE__, sql, params)
|> load_into(model)
end
defp load_into(response, model) do
Enum.map response.rows, fn(row) ->
fields = Enum.reduce(Enum.zip(response.columns, row), %{}, fn({key, value}, map) ->
Map.put(map, key, value)
end)
Ecto.Schema.__load__(model, nil, nil, [], fields, &__MODULE__.__adapter__.load/2)
end
end
Run Code Online (Sandbox Code Playgroud)
并使用如下:
Repo.execute_and_load("SELECT * FROM users WHERE id = $1", [1], User)
Run Code Online (Sandbox Code Playgroud)
除了Ecto.Adapters.SQL.query/4之外,还有Ecto.Query.API.fragment/1,它可用于将查询表达式发送到数据库.例如,要使用Postgres的数组函数array_upper,可以使用
Ecto.Query.where([x], fragment("array_upper(some_array_field, 1)]" == 1)
Run Code Online (Sandbox Code Playgroud)
Ecto 2.2.8提供了Ecto.Query.load/2,因此您可以执行以下操作:
use Ecto.Repo
def execute_and_load(sql, params, model) do
result = query!(sql, params)
Enum.map(result.rows, &load(model, {result.columns, &1}))
end
Run Code Online (Sandbox Code Playgroud)
参见https://hexdocs.pm/ecto/Ecto.Repo.html#c:load/2
Kru*_*rut -5
至少在 ecto 4.0 中,您可以使用适配器进行查询,然后将结果提供给 Ecto.Model。架构/3:
q = Ecto.Adapters.Postgres.query(Rocket.Repo,"select * from users limit 1",[])
Rocket.User.__schema__(:load,q.rows |> List.first,0)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
20128 次 |
| 最近记录: |