【问题标题】:Using has_many - belongs_to association when using UUID (String)使用 UUID(字符串)时使用 has_many - belongs_to 关联
【发布时间】:2025-12-11 05:55:02
【问题描述】:

我正在尝试关联两个模型(用户和国家/地区),其中:

· 一个国家有_many用户。

· 一个用户属于一个国家。

另外,我使用 UUID 作为两个模型的主键,所以我没有 :id 类型来关联它们,只有字符串可以做到这一点。 这些国家是静态的,但我会创造很多用户。

我应该如何关联这两个模型以及我应该在模式中的两个函数中写入哪些参数(has_many 和 belongs_to)?我应该调用哪个函数来关联它们:cast_assoc、build_assoc 还是 put_assoc?

谢谢!!

  @primary_key {:uuid, :string, []}
  @derive {Phoenix.Param, key: :uuid}
  schema "countries" do
    field :country_name, :string

    has_many :users, UserManagement.User, foreign_key: :country_id
  end
  @primary_key {:uuid, :string, []}
  @derive {Phoenix.Param, key: :uuid}
  schema "users" do
    field :nickname, :string
    field :password, :string, virtual: true

    belongs_to :country, UserManagement.Country, references: :uuid

    timestamps()
  end

【问题讨论】:

    标签: elixir phoenix-framework uuid has-many belongs-to


    【解决方案1】:

    您可以在belongs_to: 中传递:type 选项:

    belongs_to :country, UserManagement.Country, references: :uuid, type: :string
    

    所有关联函数和助手都应该可以工作。您可以在此处找到所有可用选项:https://hexdocs.pm/ecto/Ecto.Schema.html#belongs_to/3


    如果您希望所有架构都使用 UUID,您可以将设置封装在自定义模块中,如下所示:

    defmodule MyApp.Schema do
      defmacro __using__(_) do
        quote do
          use Ecto.Schema
          @primary_key {:uuid, :string, []}
          @foreign_key_type :string
          @derive {Phoenix.Param, key: :uuid}
        end
      end
    end
    

    现在你用use MyApp.Schema代替use Ecto.Schema

    【讨论】:

    • 非常感谢!这个“使用”实现起来也很有趣!
    【解决方案2】:

    如果您使用 Jose Valim 接受的答案,并且还在自定义架构 @primary_key 上设置 autogenerate: true,您将希望 MyApp.Schema 模块使用类型 Ecto.UUID

    这看起来像:

    @primary_key {:uuid, Ecto.UUID, autogenerate: true}
    

    如果不是,使用此基本架构的架构将抛出 (ArgumentError) field :uuid does not support :autogenerate because it uses a primitive type :string

    【讨论】: