使用自定义sql而不是表返回ecto模型

时间:2018-06-27 15:28:50

标签: elixir ecto

在这种情况下,我会生成带有一些自定义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方法的自定义结构,而不必担心通过架构进行备份吗?

同样,请不要再说我只读取这些数据。

1 个答案:

答案 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就可以了。