Elixir中如何使用has_one关联非主键列?
问题描述
我有一张user_reward_entries表,其Ecto Schema定义如下:
@primary_key false schema "user_reward_entries" do field(:id, Ecto.UUID, primary_key: true, read_after_writes: true) field(:amount, :integer) ... belongs_to(:transaction, Transaction) belongs_to(:user, User) timestamps() end
该表的复合主键由id和user_id组成,通过belongs_to关联了transactions表。
现在我尝试在accounts_transactions表的Schema中反向关联user_reward_entries表,Schema定义如下:
@primary_key false schema "accounts_transactions" do field(:id, Ecto.UUID, primary_key: true, read_after_writes: true) ... has_one :user_reward_entry, UserRewardEntry field(:completed_at, :utc_datetime_usec) timestamps() end
执行时遇到错误:
need to set :references option for association :user_reward_entry when schema has no primary key
随后我尝试设置:references选项:
has_one :user_reward_entry, UserRewardEntry, references: UserRewardEntry, foreign_key: :transaction_id
但又出现错误:
schema does not have the field SharedDb.Models.Rewards.UserRewardEntry used by association :user_reward_entry, please set the :references option accordingly
我还尝试过:
has_one :user_reward_entry, UserRewardEntry, references: UserRewardEntry, foreign_key: :transaction
但得到相同的错误,请问正确的做法是什么?
解决方法
核心错误是对:references参数的理解偏差:
:references需要指定当前Schema(即accounts_transactions对应的Transaction Schema)中的字段名,这个字段是被关联表(user_reward_entries)外键的引用目标。- 你之前把
references设成了UserRewardEntry模块,完全不符合Ecto的参数要求。
正确的关联写法如下:
has_one :user_reward_entry, UserRewardEntry, foreign_key: :transaction_id, references: :id
参数说明
foreign_key: :transaction_id:指定user_reward_entries表中关联当前表的外键字段(对应belongs_to(:transaction, Transaction)自动生成的外键)。references: :id:指定当前表(accounts_transactions)中被外键引用的主键字段,即Transaction的id字段。
补充说明
虽然user_reward_entries用了复合主键,但当前场景是建立“交易-奖励条目”的一对一关联,仅需基于transaction_id即可完成约束。如果后续需要基于复合主键做更严格的关联,可以在关联中添加where条件限制user_id,但当前写法已足够解决问题。
内容的提问来源于stack exchange,提问作者jhamm
相关产品推荐
相关产品推荐

