Insert Ecto model with already existing model as an association

I have 2 models, entries :

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

And exceptions :

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

The migration script:

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

My goal is to store exceptions that happen in another system. I want the project to be able to store each exception in the second table exception if they are not already there and then store the application name and the exception id in the first table entries . There will be 1000s of records in entries and a handful in exceptions .

Assuming entry_params uses this JSON format:

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

the method that should create the entries:

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

This will print out:

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

If I change the entries model to use has_one instead of belongs_to (and I think belongs_to "feels" bad here. An entry does not belong to an exception, it just has an exception) it throws the following:

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

     table: entries
     column: exception_id

What I want basically to first create an Exception (if it does not exist) and than create a new Entry of a system error and put the previously begotten Exception in the entry as an association.

What is wrong here?


  • Typo . belongs_to :exception, Proj.Exception should be belongs_to :exceptions, Proj.Exception
  • Association . Based on the data model in the question, I think the put_assoc is the wrong way around because in the data schema in the question, an exception has_many entries and an entry belongs_to exceptions. Ecto.Changeset.put_assoc(entries_changeset, :exception, exception) should be Ecto.Changeset.put_assoc(exception_changeset, :entries, entries)
  • Attempted solution:

    entries schema:

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

    exceptions schema:

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

    migration script:

    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
    

    Assuming entry_params uses this JSON format:

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

    create or update the exceptions and the associated 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/90988.html

    上一篇: Swift 2.2泛型的问题(Xcode 7.3)

    下一篇: 将已有模型的Ecto模型插入为关联