【问题标题】:Back an ecto model with custom sql instead of a table使用自定义 sql 而不是表来支持 ecto 模型
【发布时间】:2018-06-28 14:00:41
【问题描述】:

我遇到了这种情况,我使用一些自定义 sql 生成了一个中间表。在我的应用程序中,我有一个指向该中间表的模型。我有这个不使用中间表的要求,所以我试图弄清楚如何编写一个 Ecto 模型,以便它使用该自定义 sql 为该模型加载数据。

重要提示:此模型仅用于读取该表或 sql 选择结果,因此我不必支持插​​入/更新/删除。这应该会大大简化我正在尝试做的事情。

这是我想做的假模型:

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 方法的自定义结构,而不用担心用架构支持它?

再次,请不要说我只是在阅读这些数据。

【问题讨论】:

  • Ecto.Schema 是完美的生活,没有任何真正的桌子;我经常使用Ecto.Schema 来方便地验证结构。除此之外,我不确定我是否了解问题所在。您是否需要它完全符合Ecto 以便您可以在复杂的查询中使用它?
  • 不,我只需要能够加载一组行并像访问任何结构一样访问它们。 (例如mystruct.id)我想知道我是否只是创建了一个与 ecto 模型/模式机制无关的结构,并有一个执行 sql 并将其映射到结构中的方法
  • 另外,如果您不使用真实表支持模型架构的代码,它会是什么样子?
  • 如果你想要一个不受表支持的架构hexdocs.pm/ecto/Ecto.Schema.html#embedded_schema/1,你可以使用embedded_schema

标签: elixir ecto


【解决方案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 即可。

【讨论】:

    猜你喜欢
    • 2016-01-02
    • 1970-01-01
    • 2013-06-25
    • 1970-01-01
    • 2016-12-06
    • 2016-02-06
    • 2023-01-03
    • 1970-01-01
    • 2012-03-23
    相关资源
    最近更新 更多