使用自定义 sql 而不是 table 返回 ecto 模型
Back an ecto model with custom sql instead of a table
我遇到了这种情况,我生成了一个带有一些自定义 sql 的中间 table。在我的应用程序中,我有一个模型指向那个中间 table。我有这个要求不使用中间 table,所以我试图弄清楚如何编写 Ecto 模型,以便它使用自定义 sql 加载数据型号。
重要提示:此模型仅用于读取 table 或 sql select 结果,因此我不必支持 insert/update/delete。这应该会大大简化我正在尝试做的事情。
这是我想要做的假模型:
defmodule EventBridge.C3poEvent do
use Ecto.Schema
import Ecto
import Ecto.Query, only: [from: 1, from: 2]
schema intermediate_table_name do
field :id, :integer
field :access_dates, :string
field :action, :string
field :counter, :integer
end
end
让我们假设这个 sql 来获取数据:
select id, access_dates, action, counter from some_other_table
where some_conditions = true;
我需要做的是使用 sql 加载模型,而不是从 table 我的示例支持。
在我的脑海里,我在想我应该在模型中加入一个函数,比如:
def get_model(Model, some_conditions) do
...
end
并且在该函数中只需手动加载其中包含 sql 的模型。但我不相信这 a) 有意义或 b) 会产生一个我可以用来访问字段的模型。
也许我什至不应该使用模型?只是一个自定义结构,里面有 get_model 方法,不用担心用模式支持它?
再一次,请不要说我只读过这些数据。
如果我正确理解了您的需求,您只需要一种“升级”的结构。使用 Ecto.Schema.embedded_schema/1
很容易实现这一点。我会提供一个从我的生产代码示例中采纳的示例,显示验证和其他 Ecto
优点:
defmodule EventBridge.C3poEvent do
use Ecto.Schema
import Ecto.Changeset
@required_fields ~w|id access_dates action|
@fields ["counter" | @required_fields]
@primary_key false
embedded_schema do
field :id, :integer
field :access_dates, :string
field :action, :string
field :counter, :integer
end
def new(data) when is_map(data) do
%__MODULE__{}
|> cast(data, @fields) # free from Ecto
|> validate_required(@required_fields) # free from Ecto
|> apply_changes() # free from Ecto
end
## `to_string` / interpolation support
defimpl String.Chars, for: EventBridge.C3poEvent do
def to_string(term) do
"<[#{access_dates} #{action}(#{counter})]>"
end
end
## `inspect` support
defimpl Inspect, for: EventBridge.C3poEvent do
import Inspect.Algebra
def inspect(%{
id: id,
access_dates: access_dates,
action: action,
counter: counter}, opts) do
inner = [id: id, access_dates: access_dates,
action: action, counter: counter]
concat ["#EventBridge.C3poEvent<", to_doc(inner, opts), ">"]
end
end
end
以上是 Ecto
支持的任何“升级”结构的现成脚手架。一旦决定将其存储在数据库中,只需从 embedded_schema
切换到 schema
即可。
我遇到了这种情况,我生成了一个带有一些自定义 sql 的中间 table。在我的应用程序中,我有一个模型指向那个中间 table。我有这个要求不使用中间 table,所以我试图弄清楚如何编写 Ecto 模型,以便它使用自定义 sql 加载数据型号。
重要提示:此模型仅用于读取 table 或 sql select 结果,因此我不必支持 insert/update/delete。这应该会大大简化我正在尝试做的事情。
这是我想要做的假模型:
defmodule EventBridge.C3poEvent do
use Ecto.Schema
import Ecto
import Ecto.Query, only: [from: 1, from: 2]
schema intermediate_table_name do
field :id, :integer
field :access_dates, :string
field :action, :string
field :counter, :integer
end
end
让我们假设这个 sql 来获取数据:
select id, access_dates, action, counter from some_other_table
where some_conditions = true;
我需要做的是使用 sql 加载模型,而不是从 table 我的示例支持。
在我的脑海里,我在想我应该在模型中加入一个函数,比如:
def get_model(Model, some_conditions) do
...
end
并且在该函数中只需手动加载其中包含 sql 的模型。但我不相信这 a) 有意义或 b) 会产生一个我可以用来访问字段的模型。
也许我什至不应该使用模型?只是一个自定义结构,里面有 get_model 方法,不用担心用模式支持它?
再一次,请不要说我只读过这些数据。
如果我正确理解了您的需求,您只需要一种“升级”的结构。使用 Ecto.Schema.embedded_schema/1
很容易实现这一点。我会提供一个从我的生产代码示例中采纳的示例,显示验证和其他 Ecto
优点:
defmodule EventBridge.C3poEvent do
use Ecto.Schema
import Ecto.Changeset
@required_fields ~w|id access_dates action|
@fields ["counter" | @required_fields]
@primary_key false
embedded_schema do
field :id, :integer
field :access_dates, :string
field :action, :string
field :counter, :integer
end
def new(data) when is_map(data) do
%__MODULE__{}
|> cast(data, @fields) # free from Ecto
|> validate_required(@required_fields) # free from Ecto
|> apply_changes() # free from Ecto
end
## `to_string` / interpolation support
defimpl String.Chars, for: EventBridge.C3poEvent do
def to_string(term) do
"<[#{access_dates} #{action}(#{counter})]>"
end
end
## `inspect` support
defimpl Inspect, for: EventBridge.C3poEvent do
import Inspect.Algebra
def inspect(%{
id: id,
access_dates: access_dates,
action: action,
counter: counter}, opts) do
inner = [id: id, access_dates: access_dates,
action: action, counter: counter]
concat ["#EventBridge.C3poEvent<", to_doc(inner, opts), ">"]
end
end
end
以上是 Ecto
支持的任何“升级”结构的现成脚手架。一旦决定将其存储在数据库中,只需从 embedded_schema
切换到 schema
即可。