Ответ 1
EDIT: я обновил этот ответ на Ecto v2.0. Вы можете прочитать предыдущий ответ в конце.
Ecto v2
Обработка UUID в Ecto стала намного более прямой с момента первоначального ответа. Ecto имеет два типа идентификаторов: :id
и :binary_id
. Первый - это целочисленный идентификатор, который мы знаем из баз данных, второй - двоичный файл базы данных. Для Postgres это UUID.
Чтобы иметь UUID в качестве первичных ключей, сначала укажите их в своей миграции:
create table(:posts, primary_key: false) do
add :id, :binary_id, primary_key: true
end
Затем в вашем модуле модели (вне блока schema
):
@primary_key {:id, :binary_id, autogenerate: true}
Когда вы укажете опцию :autogenerate
для :binary_id
, Ecto гарантирует, что либо адаптер, либо база данных сгенерируют его для вас. Однако вы можете создать его вручную, если хотите. Btw, вы могли бы использовать :uuid
в своей миграции и Ecto.UUID
в вашей схеме вместо :binary_id
, преимущество :binary_id
в том, что оно переносимо через базы данных.
Ecto v1
Вы должны сообщить своей базе данных, как автоматически генерировать UUID для вас. Или вам нужно создать его со стороны приложения. Это зависит от того, какой вы предпочитаете.
Прежде чем двигаться дальше, важно сказать, что вы используете :uuid
, который будет возвращать двоичные файлы вместо человекообразных UUID. Скорее всего, вы захотите использовать Ecto.UUID
, который отформатирует его как строку (aaaa-bbb-ccc -...) и что я буду использовать ниже.
Генерация в базе данных
В вашей миграции укажите значение по умолчанию для поля:
add :id, :uuid, primary_key: true, default: fragment("uuid_generate_v4()")
Я предполагаю, что вы работаете на PostgreSQL. Вам необходимо установить расширение uuid-ossp с помощью CREATE EXTENSION "uuid-ossp"
в pgAdmin или добавить execute "CREATE EXTENSION \"uuid-ossp\""
в перенос. Более подробную информацию о генератор UUID можно найти здесь.
Обратно в Ecto, в вашей модели, попросите Ecto прочитать поле из базы данных после вставки/обновления:
@primary_key {:id, Ecto.UUID, read_after_writes: true}
Теперь, когда вы вставляете, база данных будет генерировать значение по умолчанию, а Ecto будет читать его.
Создание в приложении
Вам нужно будет определить модуль, который вставляет UUID для вас:
defmodule MyApp.UUID do
def put_uuid(changeset) do
Ecto.Changeset.put_change(changeset, :id, Ecto.UUID.generate())
end
end
И используйте его как обратный вызов:
def model do
quote do
use Ecto.Model
@primary_key {:id, Ecto.UUID, []}
@foreign_key_type Ecto.UUID
before_insert MyApp.UUID, :put_uuid, []
end
end
before_insert
является обратным вызовом, и он будет вызывать данный модуль в данной функции с заданными аргументами, а набор изменений, представляющий то, что вводится, задается как первый аргумент.
Это все. Кстати, есть шанс, что это будет более оптимизировано в будущем.:)