将已有模型的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如果它们不在那里),然后将应用程序名称和异常ID存储在第一个表entriesentries会有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 (我认为belongs_to在这里“感觉不好”,条目不属于异常,它只是有一个例外),它会抛出以下内容:

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

     table: entries
     column: exception_id

我基本上想要首先创建一个异常(如果它不存在),并创建一个新的系统错误条目并将以前生成的异常作为关联添加到条目中。

这里有什么问题?


  • 错字belongs_to :exception, Proj.Exception应该是belongs_to :exceptions, Proj.Exception
  • 协会 。 根据问题中的数据模型,我认为put_assoc是一个错误的方法,因为在问题的数据模式中,has_many条目和一个条目belongs_to异常是一个例外。 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
    
    链接地址: http://www.djcxy.com/p/90987.html

    上一篇: Insert Ecto model with already existing model as an association

    下一篇: How to chain rxjs observable