Как правильно написать транзакцию и исправить ошибки - PullRequest
0 голосов
/ 19 декабря 2018

Хорошо, из-за нескольких уровней отдачи, я немного растерялся.

Я очень плохо знаком с экто, так что здесь.

Я пытаюсь завершить создание своей учетной записи втранзакция, потому что она создает много дочерних записей и т. д.

Итак, пока у меня есть это:

def create_account(company_name, ...) do
  Repo.transaction(fn ->      
    case Account.create_account(%{
          # ... attributes here
        }) do
          ????
        end

        # insert other model records here using the same above case pattern matching

    account
  end) # transaction
end

create_account в модели схемы ecto выглядит так:

Account.ex

def create_account(attrs \\ %{}) do
  %Account{}
  |> Account.changeset(attrs)
  |> Repo.insert()
end

Итак, теперь есть 3 уровня возвращаемых значений, которые я не знаю, как обрабатывать все вместе:

  1. кажется, что счастливый путь транзакцииreturn: {: ok, модель}

  2. если вставка account.create_account завершится неудачно, как передать эти ошибки до окончательного возвращаемого значения, чтобы я мог отобразить его в пользовательском интерфейсе?

  3. как правильно выполнить откат на любом из шагов?

Ответы [ 2 ]

0 голосов
/ 19 декабря 2018

Вы должны использовать Repo.rollback при сбоях.В документах написано The transaction will return the value given as {:error, value}, так что это можно сделать с помощью сопоставления с образцом, как вы упомянули:

def create_account(company_name, ...) do
  Repo.transaction(fn ->
    account = case Account.create_account(%{ # ... attributes here }) do
      {:ok, account} -> account
      {:error, changeset} -> Repo.rollback(changeset)
    end

    # insert other model

    {:ok, account}
  end)
end

Таким образом, ваша функция вернет {:ok, account} при успехе и {:error, changeset} при любом сбое, с которым она столкнется.Поскольку вы вставляете несколько вещей, возможно, вы захотите их различить, например, так:

account = case Account.create_account(%{ # ... attributes here }) do
  {:ok, account} -> account
  {:error, changeset} -> Repo.rollback({:account, changeset})
end

case User.create_user(account, %{ # ... attributes here }) do
  {:ok, user} -> :ok
  {:error, changeset} -> Repo.rollback({:user, changeset})
end

В этом случае функция вернет {:ok, account}, если все пойдет хорошо, {:error, {:account, account_changeset}}, если вставка учетной записи не удаласьи {:error, {:user, user_changeset}} в случае сбоя вставки пользователем.

0 голосов
/ 19 декабря 2018

Использование Kernel.SpecialForms.with/1 монадоподобная специальная форма:

def create_account(company_name, ...) do
  Repo.transaction(fn ->      
    with {:ok, account} <- Account.create_account(...),
         {:ok, _} <- AnotherModel.create_record(...),
         ...
         {:ok, _} <- LastModel.create_record(...) do
      IO.puts("All fine")
      account
    else
      error ->
        IO.inspect(error, label: "Error happened") 
        Repo.rollback(:error_in_transaction)
    end
  end) # transaction
end
...