Can the Ecto schema field name different from colu

2019-07-25 17:47发布

I've got a legacy database that I'm trying to pull into Ecto. In it there's an orders table which has an order_status_id column. order_status_id maps to a set of constants in the legacy system.

I'd like to have the MyApp.Order struct contain an order_status field, which has a custom type that converts the integer IDs to meaningful atoms. I've got the custom type working, but I can't figure out how to map a field named order_status to a column named order_status_id.

The legacy system is still online and using the database, so changing the DB schema is not an option. Is there any way to get this working?

标签: elixir ecto
2条回答
男人必须洒脱
2楼-- · 2019-07-25 18:31

I'm not sure if it was possible when the question was first asked, but it is possible now (Elixir 1.5). See https://hexdocs.pm/ecto/Ecto.Schema.html In particular the @field_source_mapper and :source options. The :source option is pretty easy -- just include it in your schema definition something like this:

  schema "orders" do

    field :foo, :string, [source: :legacy_foo_db_column]
    field :status, :integer, [source: :order_status]

  end

In the above example, the existing database table has columns named "legacy_foo_db_column" and "order_status", but internally in the Elixir app, the schema and changeset etc. will use attributes named "foo" and "status"

查看更多
甜甜的少女心
3楼-- · 2019-07-25 18:39

I think, it is currently not possible to simply associate model field with different column name.

If you really want to use name order_status, you can create additional virtual field. Those fields are not persisted to database. Then your cast function should be responsible for changing order_status_id based on params.

def changeset(model, params \\ :empty) do
  model
  |> cast(params, @required_fields, @optional_fields)
  |> put_order_status_id
end

defp put_order_status_id(changeset) do
  case changeset do
    %Ecto.Changeset{valid?: true, changes: %{order_status: status}} ->
      put_change(changeset, :order_status_id, id_from_status(status))
    _ ->
      changeset
  end
end

In theory, you can also use changeset function to do the opposite operation: set order_status based on order_status_id, but it adds complexity.

In my opinion, the best solution would be to simply accept order_status_id name.

查看更多
登录 后发表回答