每当我运行此代码:
{:ok, act_1} = %Kempelen.Models.GameAct{}
|> Kempelen.Models.GameAct.changeset(%{
game_play: place_road,
game_player: player_1,
game_round: round_1
})
|> Kempelen.Database.Repo.insert
我遇到此异常:
** (Ecto.NoPrimaryKeyValueError) struct `%Kempelen.Models.GamePlayer{__meta__: #Ecto.Schema.Metadata<:loaded, "game_players">, account: %Kempelen.Models.Account{__meta__: #Ecto.Schema.Metadata<:loaded, "accounts">, email: "[email protected]", game_players: #Ecto.Association.NotLoaded<association :game_players is not loaded>, game_rounds: #Ecto.Association.NotLoaded<association :game_rounds is not loaded>, game_tables: #Ecto.Association.NotLoaded<association :game_tables is not loaded>, id: "65880220-e39b-450d-ba7f-0642bea8dbc8", inserted_at: ~N[2020-02-16 16:15:33], name: nil, onboarding_state: "converted", organization_memberships: #Ecto.Association.NotLoaded<association :organization_memberships is not loaded>, organizations: #Ecto.Association.NotLoaded<association :organizations is not loaded>, password: nil, password_hash: nil, role_state: "user", unconfirmed_email: "[email protected]", updated_at: ~N[2020-02-16 16:15:33], username: nil}, account_id: "65880220-e39b-450d-ba7f-0642bea8dbc8", game_acts: #Ecto.Association.NotLoaded<association :game_acts is not loaded>, game_robot: nil, game_robot_id: nil, game_table: %Kempelen.Models.GameTable{__meta__: #Ecto.Schema.Metadata<:loaded, "game_tables">, game: %Kempelen.Models.Game{__meta__: #Ecto.Schema.Metadata<:loaded, "games">, game_plays: #Ecto.Association.NotLoaded<association :game_plays is not loaded>, game_tables: #Ecto.Association.NotLoaded<association :game_tables is not loaded>, id: "31eee3b8-b43c-411a-8528-479269c63d2d", inserted_at: ~N[2020-02-16 16:15:33], name: "Settlers of Catan", organization: %Kempelen.Models.Organization{__meta__: #Ecto.Schema.Metadata<:loaded, "organizations">, accounts: #Ecto.Association.NotLoaded<association :accounts is not loaded>, games: #Ecto.Association.NotLoaded<association :games is not loaded>, id: "3311c337-f480-4292-9582-c45f249730b2", inserted_at: ~N[2020-02-16 16:15:32], name: "Hasbro", organization_memberships: #Ecto.Association.NotLoaded<association :organization_memberships is not loaded>, robots: #Ecto.Association.NotLoaded<association :robots is not loaded>, slug: "hasbro", updated_at: ~N[2020-02-16 16:15:32]}, organization_id: "3311c337-f480-4292-9582-c45f249730b2", slug: "settlers-of-catan", updated_at: ~N[2020-02-16 16:15:33]}, game_id: "31eee3b8-b43c-411a-8528-479269c63d2d", game_players: #Ecto.Association.NotLoaded<association :game_players is not loaded>, game_rounds: #Ecto.Association.NotLoaded<association :game_rounds is not loaded>, id: "2cda5e3c-c57d-4117-a541-0c6a409984b6", inserted_at: ~N[2020-02-16 16:15:33], name: "FFA", slug: "ffa", updated_at: ~N[2020-02-16 16:15:33]}, game_table_id: "2cda5e3c-c57d-4117-a541-0c6a409984b6", host: true, id: "591227e6-3ea0-4f3f-8a44-471d7073c2df", inserted_at: ~N[2020-02-16 16:15:33], name: "Kurtis", slug: "kurtis", updated_at: ~N[2020-02-16 16:15:33]}` is missing primary key value
这里是模特:
defmodule Kempelen.Models.GameAct do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "game_acts" do
belongs_to :game_play, Kempelen.Models.GamePlay, primary_key: true
belongs_to :game_player, Kempelen.Models.GamePlayer, primary_key: true
belongs_to :game_round, Kempelen.Models.GameRound, primary_key: true
timestamps()
end
@doc false
def changeset(%{} = record, attributes \\ %{}) do
record
|> cast(attributes, [])
|> validate_required([])
|> assoc_constraint(:game_play)
|> assoc_constraint(:game_player)
|> assoc_constraint(:game_round)
|> put_assoc(:game_play, attributes.game_play)
|> put_assoc(:game_player, attributes.game_player)
|> put_assoc(:game_round, attributes.game_round)
end
end
defmodule Kempelen.Models.GamePlayer do
use Ecto.Schema
import Ecto.Changeset
@primary_key {:id, :binary_id, autogenerate: true}
@foreign_key_type :binary_id
schema "game_players" do
field :name, :string
field :slug, Kempelen.Slugs.Name.Type
field :host, :boolean, default: false
belongs_to :game_table, Kempelen.Models.GameTable, primary_key: true
belongs_to :account, Kempelen.Models.Account, primary_key: true
belongs_to :game_robot, Kempelen.Models.GameRobot, primary_key: true
has_many :game_acts, Kempelen.Models.GameAct
timestamps()
end
@doc false
def changeset(%{} = record, attributes \\ %{}) do
record
|> cast(attributes, [:name, :host])
|> validate_required([:name, :host])
|> assoc_constraint(:game_table)
|> assoc_constraint(:account)
|> assoc_constraint(:game_robot)
|> Kempelen.Slugs.Name.maybe_generate_slug
|> Kempelen.Slugs.Name.unique_constraint
|> put_assoc(:game_robot, attributes[:game_robot])
|> put_assoc(:account, attributes[:account])
|> put_assoc(:game_table, attributes.game_table)
end
end
不仅是game_play模型,也发生在game_player中。
变更集似乎也认为它是有效的:
#Ecto.Changeset<
action: nil,
changes: %{
game_play: #Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Kempelen.Models.GamePlay<>, valid?: true>,
game_player: #Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Kempelen.Models.GamePlayer<>, valid?: true>,
game_round: #Ecto.Changeset<action: :update, changes: %{}, errors: [],
data: #Kempelen.Models.GameRound<>, valid?: true>
},
errors: [],
data: #Kempelen.Models.GameAct<>,
valid?: true
>
好,所以我终于明白了。事实证明,虽然我希望account
和game_robot
关系是可选的(在业务逻辑中一个或另一个),但是架构中primary_key: true
的belongs_to
选项意味着外键列必须具有一个值。