I have a table that I want to constrain to a single row…
def up do
create table(:config, primary_key: false) do
add :id, :integer, primary_key: true, null: false
...more fields
end
create constraint("config", :only_one_record, check: "id = 1")
execute "INSERT INTO " <> prefix() <> ".config (id, ...more fields) VALUES(1, ...);"
end
I can get the record:
Repo.get!(Config, 1,
but can’t figure out how to update
config
|> Config.update_changeset(attrs)
|> Repo.update(
** (Ecto.NoPrimaryKeyValueError) struct %Config{__meta__: #Ecto.Schema.Metadata<:built, "config">, id: nil, more fields}
is missing primary key value
I tried setting the id explicitly in the changeset, but get the same error.
fuelen
August 19, 2021, 6:40am
2
What is the value of config
before passing it to Config.update_changeset/2
?
def update_config(%Config{} = config, attrs, tenant) do
config
|> Config.update_changeset(attrs)
|> IO.inspect()
|> Repo.update(prefix: Analytics.Tenants.Actions.build_prefix(tenant))
end
ecto .Changeset<
action: nil,
changes: %{id: 1, screen_rec_storage: true, voice_rec_storage: true},
errors: ,
data: analytics .Tenants.Config<>,
valid?: true
test config settings Update config (Analytics.Tenants.TenantTest)
test/analytics/tenants_test.exs:15
** (Ecto.NoPrimaryKeyValueError) struct %Analytics.Tenants.Config{__meta__: #Ecto.Schema.Metadata<:built, "config">, id: nil, screen_rec_storage: nil, voice_rec_storage: nil}
is missing primary key value
code: assert {:ok, _} = Tenants.update_config(%Config{}, cfg, tenant)
stacktrace:
(ecto 3.6.2) lib/ecto/repo/schema.ex:932: anonymous fn/3 in Ecto.Repo.Schema.add_pk_filter!/2
(elixir 1.12.0) lib/enum.ex:2356: Enum.“-reduce/3-lists^foldl/2-0-”/3
(ecto 3.6.2) lib/ecto/repo/schema.ex:397: Ecto.Repo.Schema.do_update/4
test/analytics/tenants_test.exs:21: (test)
fuelen
August 19, 2021, 11:46am
5
Empty config is passed. Of course, id
is absent
ah, oh
Well, I guess I don’t fully understand the whole Ecto thing yet.
Thanks for the help
wayne
03juan
August 19, 2021, 11:57am
7
Yes, the schema update function executed in the stracktrace at lib/ecto/repo/schema.ex:397 calls add_pk_filter!(changeset.filters, struct)
with the struct that’s in your changeset’s :data
, which in this case is empty of values.
You have to pass in a %Config{id: 1}
struct to update_config
That is, in your code do:
assert {:ok, _} = Tenants.update_config(%Config{id: 1}, cfg, tenant)
That ends up telling Repo that you want to update the row with id of 1, if you don’t pass that in as your base data, it won’t know what to update.
You can get away with an empty %Config{}
struct when inserting because it is a new entry.
Thanks for taking the time to explain
1 Like