【发布时间】:2020-05-27 17:19:12
【问题描述】:
我必须处理我无法更改的数据库设置,并且我必须使用特定的 SQL 查询来计算不是表中字段的值。我怎样才能在 Ecto 中完成这项工作?这是我的方法和遇到的问题:
设置
$ mix phx.new testapp
$ cd testapp
$ mix ecto.create
$ mix phx.gen.html Shops Product products name price:float
$ mix ecto.migrate
之后我创建了几个产品。
x
我在product 中添加了一个虚拟的x 字段:
lib/testapp/shops/product.ex
defmodule Testapp.Shops.Product do
use Ecto.Schema
import Ecto.Changeset
schema "products" do
field :name, :string
field :price, :float
field :x, :integer, virtual: true # <-----
timestamps()
end
@doc false
def changeset(product, attrs) do
product
|> cast(attrs, [:name, :price])
|> validate_required([:name, :price])
end
end
我将以下函数添加到Testapp.Shops:
def execute_and_load(sql, params, model) do
result = Ecto.Adapters.SQL.query!(Repo, sql, params)
Enum.map(result.rows, &Repo.load(model, {result.columns, &1}))
end
def list_products_with_x do
sql = "SELECT *, 1 AS x FROM products;" # <- simplified
execute_and_load(sql, [], Testapp.Shops.Product)
end
1 AS x 和整个 SQL 查询只是一个简化的例子!在实际应用程序中,我必须使用调用存储过程的 SQL 查询来进行计算,并将值存储在x 中。所以会有一些我不能用 Ecto 本身创建的 SQL。如果您对 SQL 感兴趣:
Overlapping gaps and islands in a school vacation setup
问题
SQL 查询为每个条目提供x 的值,但product 将x 列为nil。我怎么解决这个问题?如何填写execute_and_load/3 中的virtual 字段?
iex(1)> Testapp.Shops.list_products_with_x
[debug] QUERY OK db=1.3ms queue=2.2ms idle=8177.7ms
SELECT *, 1 AS x FROM products; []
[
%Testapp.Shops.Product{
__meta__: #Ecto.Schema.Metadata<:loaded, "products">,
id: 1,
inserted_at: ~N[2020-02-12 07:29:36],
name: "Apple",
price: 0.5,
updated_at: ~N[2020-02-12 07:29:36],
x: nil
},
%Testapp.Shops.Product{
__meta__: #Ecto.Schema.Metadata<:loaded, "products">,
id: 2,
inserted_at: ~N[2020-02-12 07:29:47],
name: "Orange",
price: 0.75,
updated_at: ~N[2020-02-12 07:29:47],
x: nil
}
]
我对给定问题的替代解决方案持开放态度。我无法在我的 Elixir 程序中计算 x 的值。我必须使用 SQL 来计算它,我想使用 Ecto。
【问题讨论】:
标签: elixir phoenix-framework ecto