数日前、PostgresデータベースでElixirとPhoenix Framework(v 0.12.0)を使い始めました。 UUIDプライマリキーを持つテーブルを作成しようとしています。これはシーケンシャルデフォルトよりも優先されます。
mix phoenix.gen.html
を使用してモデルと移行ファイルを生成し、Phoenixドキュメントの他の手順を実行した後、変更しました
def model do
quote do
use Ecto.Model
end
end
web.ex
から
def model do
quote do
use Ecto.Model
@primary_key {:id, :uuid, []}
@foreign_key_type :uuid
end
end
ectoのドキュメントに記載されているように。また、移行をに変更しました
create table(:tblname, primary_key: false) do
add :id, :uuid, primary_key: true
[other columns]
end
残念ながら、自動生成されたフォームからテーブルにエントリを追加しようとすると、id
がnullであるため、エラーが発生します。モデルにid
-列を手動で追加すると、列がすでに存在するというエラーが表示されます。 primary_key
でtable/2
をfalseに設定し、id
列を削除しなかった場合、テーブルは連続したid
-列で生成されます。
チェンジセットでid
を手動で設定する必要がありますか、それともUUIDを使用するようにアプリを設定する際にエラーが発生しましたか?前もって感謝します
編集:私はこの回答をEctov2.0に更新しました。最後に前の答えを読むことができます。
EctoでのUUIDの処理は、最初の回答以降、はるかに簡単になりました。 Ectoには、:id
と:binary_id
の2種類のIDがあります。 1つ目はデータベースからわかる整数IDで、2つ目はデータベース固有のバイナリです。 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はアダプターまたはデータベースのいずれかがそれを生成することを保証します。ただし、必要に応じて手動で生成することもできます。ところで、移行では:uuid
を使用し、スキーマではEcto.UUID
の代わりに:binary_id
を使用することもできます。:binary_id
の利点は、データベース間で移植できることです。
UUIDを自動的に生成する方法をデータベースに指示する必要があります。または、アプリケーション側から生成する必要があります。それはあなたがどちらを好むかによります。
先に進む前に、人間が読み取れるUUIDの代わりにバイナリを返す:uuid
を使用していることを伝えることが重要です。文字列(aaaa-bbb-ccc -...)としてフォーマットするEcto.UUID
を使用する可能性が非常に高く、これを以下で使用します。
移行では、フィールドのデフォルトを定義します。
add :id, :uuid, primary_key: true, default: fragment("uuid_generate_v4()")
PostgreSQLで実行していることを前提としています。 pgAdminにCREATE EXTENSION "uuid-ossp"
を指定してuuid-ossp拡張機能をインストールするか、移行にexecute "CREATE EXTENSION \"uuid-ossp\""
を追加する必要があります。 IDジェネレーターはここにあります に関する詳細情報。
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
はコールバックであり、指定された関数で指定されたモジュールを指定された引数で呼び出します。挿入されているものを表すチェンジセットが最初の引数として指定されます。
それがすべてのはずです。ところで、これは将来さらに合理化される可能性があります。 :)
また、新しいプロジェクトパスオプションを作成する場合--binary-id
UUIDをデフォルトの主キーとして使用します。(開始Ecto v2)
mix phx.new project_name --binary-id