Настроить функцию автогенерации первичного ключа в Ecto?

#elixir #phoenix-framework #ecto

#elixir #phoenix-framework #ecto

Вопрос:

В схеме Ecto можно указать автоматически созданный первичный ключ с помощью @primary_key атрибута:

 @primary_key {:id, :binary_id, autogenerate: true}
  

Есть ли способ указать пользовательскую функцию для autogenerate ? Я полагаю, что в этом случае он будет использовать Ecto.UUID.generate , тогда как я хотел бы использовать UUID v1.

Ответ №1:

Согласно официальной документации, вы можете создать свой собственный первичный ключ.

Вот краткий пример для установки name в качестве первичного ключа:

допустим, мы сгенерировали Player таблицу со следующей задачей смешивания :

mix phoenix.gen.json Player players name:string position:string number:integer

при миграции установите create table с помощью primary_key: false и добавьте primary_key: true в поле имя :

   def change do
    create table(:players, primary_key: false) do
      add :name, :string, primary_key: true
      add :position, :string
      add :number, :integer

      timestamps
    end
  end
  

Затем в вашей схеме все, что вам нужно сделать, это сообщить Ecto, что первичный ключ теперь является строкой ( @primary_key {:name, :string, []} ) и что идентификатор, который будет использоваться (например, в маршрутах), будет name @derive {Phoenix.Param, key: :name} . Также не забудьте удалить field :name, :string .

 defmodule Hello.Player do
  use Hello.Web, :model

  @primary_key {:name, :string, []}
  @derive {Phoenix.Param, key: :name}
  schema "players" do
    field :position, :string
    field :number, :integer

    timestamps
  end
  

Что вы можете сделать в вашем случае, так это настроить свое собственное поле в качестве первичного ключа, а затем заполнить его в наборе изменений с помощью метода, который генерирует идентификатор с UUID v1, когда вы сохраняете свои данные в своей базе данных.

Вы можете воспользоваться пакетом UUID, который имеет метод UUID v1.

Не уверен, что это лучшее обходное решение, но я надеюсь, что это поможет вам 🙂

Комментарии:

1. Это имеет смысл, спасибо. Я знаю, что могу установить пользовательский идентификатор в каждом наборе изменений, но поскольку это то, что я хотел бы сделать для всех схем во всех наборах изменений, которые создают новую запись, я надеюсь найти способ настроить функцию генерации пользовательского идентификатора в одном месте для всего …

2. @FeifanZ вы нашли лучшее решение этой проблемы? Мне любопытно, как вы справились с этим 🙂

3. Я не нашел лучшего решения этой конкретной проблемы, но вместо этого нашел альтернативный подход. Изначально я думал, что мне нужен UUID v1 для сортировки, но оказывается, что мне это строго не нужно, поэтому UUID v4 в порядке.

Ответ №2:

Вот мое решение

 #Custom string type (example of Ecto.UUID)
defmodule Ecto.UUID.AutoGenerate do
  use Ecto.Type
  def type, do: :string
  def cast(uuid), do: {:ok, uuid}
  def dump(uuid), do: {:ok, uuid}
  def load(uuid), do: {:ok, uuid}
  def autogenerate, do: Ecto.UUID.generate() # <- update your version here
end
# In your schema
defmodule PosService.Weathers.Weather do
  use Ecto.Schema
  import Ecto.Changeset
  @primary_key {:id, Ecto.UUID.AutoGenerate, autogenerate: true}
  @foreign_key_type :string
  schema "weathers" do
    field :city, :string
    field :prcp, :float
    field :temp_hi, :integer
    field :temp_lo, :integer
    timestamps()
  end
end