Я имею дело с настройкой базы данных, которую я не могу изменить, и я должен использовать конкретный запрос c SQL, который вычисляет значения, которые не являются полями в таблице. Как я могу сделать эту работу в Экто? Вот мой подход и проблема, с которой я столкнулся:
Настройка
$ mix phx.new testapp
$ cd testapp
$ mix ecto.create
$ mix phx.gen.html Shops Product products name price:float
$ mix ecto.migrate
После этого я создаю пару продуктов.
x
Я добавляю виртуальное x
поле в product
:
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
. Так что будет какой-то SQL, который я не могу создать с помощью самого Ecto. Если вас интересует SQL: Перекрывающиеся пробелы и острова в настройке школьных каникул
Проблема
Запрос SQL предоставляет значение для x
для каждой записи, но product
перечисляет x
как nil
. Как я могу решить эту проблему? Как я могу заполнить virtual
поля в execute_and_load/3
?
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
}
]
Я открыт для альтернативных решений данной проблемы. Я не могу рассчитать значение x
в моей программе Elixir. Я должен использовать SQL, чтобы вычислить это, и я хочу использовать Ecto.