Proper way to constraint removal of association when using drop_param in Ecto changeset

I’d like to have opinnion of anyone experienced in using Ecto :drop_param with nested changesets. Problem at hand is that, I would like to restrict the removal of certain association, if that association is referenced by another model in database.

I have structure similar to below, and when there are answers that belong to specific question or option removing that association from survey should not be possible.

Survey has_many Question
Question has_many Option
Option belongs_to Question
Answer belongs_to Question
Answer belongs_to Option

Form

<.form
  for={@form}
  id="survey-form"
  phx-target={@target}
  phx-change="validate"
  phx-submit="save"
>
  <.inputs_for :let={question} field={@form[:questions]}>
    <label>
      <input
        type="checkbox"
        name="event[questions_delete][]"
        value={question.index}
        class="hidden"
      />
      <%= gettext("Remove question") %>
    </label>
  </.inputs_for>
</.form>

Changeset

def changeset(question, attrs \\ %{}, index) do
  question
  |> cast(attrs, [:id])
  |> change(index: index)
  |> cast_questions(attrs)
end

defp cast_questions(changeset, attrs) do
  changeset
  |> validate_question_removal(attrs)
  |> case do
    changeset ->
      opts = questions_opts(changeset)

      changeset
      |> cast_assoc(:questions, opts)
      |> validate_length(:questions, max: 25)
  end
end

defp questions_opts(changeset) do
  opts = [
    with: &Question.changeset/3,
    sort_param: :questions_order
  ]

  if Enum.any?(changeset.errors, &drop_param_error?/1),
    do: opts,
    else: opts ++ [drop_param: :questions_delete]
end

defp drop_param_error?({:drop_param, _}), do: true
defp drop_param_error?(_), do: false

defp validate_question_removal(changeset, attrs) do
  delete_index = attrs |> Map.get("questions_delete", []) |> List.first(nil)

  question_id =
    attrs
    |> Map.get("questions", %{})
    |> Map.get(delete_index, %{})
    |> Map.get("id", nil)

  if delete_index && question_id do
    option_query =
      from(a in Answer, where: a.question_id == ^question_id)

    if Repo.Read.exists?(option_query),
      do:
        add_error(
          changeset,
          :drop_param,
          "cannot remove a question that has associated answers"
        ),
      else: changeset
  else
    changeset
  end
end

This approach does work, and has behaviour I am expecting (instead of removing the association display error message on the form eg. questions has associated answers and cannot be removed).

This approach seems a little fragile though, and I have been thinking whether something like Ecto no_assoc_constraint/3 could be used instead? Ecto.Changeset — Ecto v3.10.3

Or are there some better streamlined approach to add constraint in case of using :drop_param to do some validation before dropping the parameter.