在这种情况下,我会生成带有一些自定义sql的中间表。在我的应用程序中,我有一个指向该中间表的模型。我有一个不使用中间表的要求,所以我试图弄清楚如何编写Ecto模型,使其在加载该模型的数据时使用该自定义sql。
重要提示:此模型仅用于从该表或sql select结果中读取,因此我不必支持插入/更新/删除。那应该大大简化我的工作。
出于我想做的事情,这是一个假模型:
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而不是从我的示例所支持的表中加载模型。
在我脑海中,我想在模型中放置一个函数,例如:
def get_model(Model, some_conditions) do
...
end
,然后在该函数中手动加载其中带有sql的模型。但是我不认为这是a)有意义的,或者b)会导致我可以使用该模型来访问字段。
也许我什至不应该使用模型?只是其中具有get_model方法的自定义结构,而不必担心通过架构进行备份吗?
同样,请不要再说我只读取这些数据。
答案 0 :(得分:1)
如果我正确理解了您的需求,则只需要一种“升级的”结构即可。使用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
就可以了。