Вставить модель Ecto с уже существующей моделью в качестве ассоциации

У меня есть 2 модели, entries:

schema "entries" do
  belongs_to :exception, Proj.Exception
  field :application, :string
end

И exceptions:

schema "exceptions" do
  field :name, :string
end

Скрипт миграции:

def change do
  create table(:exceptions) do
    add :name, :string, null: false
  end

  create table(:entries) do
    add :exception_id, references(:exceptions), null: false
    add :application, :string, null: false
  end
end

Моя цель - хранить исключения, которые происходят в другой системе. Я хочу, чтобы проект мог хранить каждое исключение во второй таблице exception, если их там нет, а затем сохранить имя приложения и идентификатор исключения в первой таблице entries. В entries будет 1000 записей и несколько записей в exceptions

Предполагая, что entry_params использует этот формат JSON:

{
  exception: "NPE",
  application: "SomeApp"
}

метод, который должен создавать записи:

def create(conn, %{"entry" => entry_params}) do
  exception = Repo.get_by(Exception, name: entry_params["exception"]) || 
    Repo.insert!(%Exception{name: entry_params["exception"]})

  changeset =
    Entry.changeset(%Entry{}, entry_params)
    |> Ecto.Changeset.put_assoc(:exception, exception)

  Repo.insert!(changeset)
end

Это распечатает:

** (ArgumentError) unknown assoc `exception` in `put_assoc`

Если я изменю модель entries, чтобы использовать has_one вместо belongs_to (и я думаю, что здесь_получает "плохо". Запись не принадлежит исключению, она просто есть исключение) выдает следующее:

** (Postgrex.Error) ERROR (not_null_violation): null value in column "exception_id" violates not-null constraint

     table: entries
     column: exception_id

Что я хочу в основном, чтобы сначала создать исключение (если оно не существует), а затем создать новую запись системной ошибки и поместить ранее созданное исключение в запись как ассоциацию.

Что здесь не так?

7 голосов | спросил SLOBY 28 MaramMon, 28 Mar 2016 05:01:35 +03002016-03-28T05:01:35+03:0005 2016, 05:01:35

1 ответ


0
  • опечатка . belongs_to :exception, Proj.Exception должно быть belongs_to :exceptions, Proj.Exception
  • Ассоциация . Основываясь на модели данных в вопросе, я думаю, что put_assoc - неправильный путь, потому что в схеме данных в вопросе есть исключение has_many entry и запись принадлежит к исключениям . Ecto.Changeset.put_assoc(entries_changeset, :exception, exception) должно быть Ecto.Changeset.put_assoc(exception_changeset, :entries, entries)

Попытка решения:

entries схема:

schema "entries" do
  field :application, :string
  belongs_to :exceptions, Proj.Exception, on_replace: :nilify
end

exceptions схема:

schema "exceptions" do
  field :name, :string
  has_many :entry, Proj.Entry, on_delete: :delete_all, on_replace: :delete
end

сценарий миграции:

def change do
  create table(:exceptions) do
    add :name, :string, null: false
  end

  create table(:entries) do
    add :application, :string, null: false
    add :exception_id, references(:exceptions)
  end
end

Предполагая, что entry_params использует этот формат JSON:

{
  exception: "NPE",
  application: "SomeApp"
}

создайте или обновите exceptions и связанный с ним entries:

def create(conn, %{"entry" => entry_params}) do
  new_entry = Entry.changeset(%Entry{}, entry_params)

  changeset = 
  case Repo.get_by(Exception, name: entry_params["exception"]) do
    :nil -> 
      exception = %Exception{name: entry_params["exception"]} |> Repo.insert!
      Ecto.Changeset.build_assoc(exception, :entries, [new_entry])
    struct -> 
      changeset = Ecto.Changeset.change(struct) 
      data = Ecto.Changeset.preload(changeset, :entries) |> Map.get(:model) # Ecto 1.x
      # data = Ecto.Changeset.preload(changeset, :entries) |> Map.get(:data) # Ecto 2.0.x
      Ecto.Changeset.put_assoc(changeset, :entries, [new_entry | data.entries])
  end 

  Repo.insert!(changeset)
end
ответил stephen_m 28 MaramMon, 28 Mar 2016 10:26:36 +03002016-03-28T10:26:36+03:0010 2016, 10:26:36

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132