Trying to find elegant solutions to upsert embedded associations

I’m building a finance tracking Phoenix LiveView application in which I have a Transaction schema that embeds (via belongs_to) a Merchant schema. The merchant represents where the transaction took place, so naturally, one can have multiple transactions per merchant.

I also have basic forms that allow creating and editing transactions. The complication here is that I want to be able to type in a free-form merchant name and have that upsert a corresponding Merchant in the backend. This prevents me from having the form be backed by a changeset for the Transaction schema since when I’m editing a transaction’s merchant, I want to upsert a new Merchant with the updated name rather than updating the existing merchant (which would affect all transactions that were referencing the old merchant).

What I’ve done to work around this is create a TransactionForm embedded schema that backs the form. Then when I decide to save the form, I’ll pull out the merchant name, upsert that, grab the ID, and then create a Transaction changeset with the remaining parameters and the (possibly updated) merchant ID.

I can see how this would make a lot of sense for more complex forms, but this seems repetitive for my use case since it’s duplicating a lot of the changeset validations I have in place for the Transaction schema with the only meaningful change being it has merchant instead of merchant_id as a field. Transactions have a bunch of other fields that I haven’t specified here since they’re not relevant to the example, but the validation for all those fields have to be copied as well.

I’m hoping (and assuming) that I’m not the first to encounter this and that a more elegant solution exists.

I’ve read through this page from the Ecto documentation, but I was turned off and a bit surprised by the inclusion of side effects (writing to the DB) in the changeset. My form is validated in realtime as the form values are updated, so I don’t think it’s reasonable to be writing to the DB for each keystroke.

Thank you in advance!