代码之家  ›  专栏  ›  技术社区  ›  code.cycling

insert\u all与类型不匹配:utc\u datetime

  •  1
  • code.cycling  · 技术社区  · 6 年前

    我想用 insert_all . 我得到一个错误,我的一个字段不匹配。

    {
    "edtrs":
    [
        {
            "dtr_date": "2018-12-29T16:00:00.000Z",
            "user_id": "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
        },
        {
            "dtr_date": "2018-12-30T16:00:00.000Z",
            "user_id": "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
        }
    ]}
    

     def create_edtr(edtrs) do
    maps =
      Enum.map(edtrs["edtrs"], fn(item) ->
        %{dtr_date: item["dtr_date"], user_id: item["user_id"]}
      end)
    
    IO.inspect maps, label: "MAPS"
    Repo.insert_all(Edtr,maps) end
    

    错误

    HrisApp.Attendance.Edtr.dtr_date 全部插入 与类型不匹配 :utc_datetime

    2 回复  |  直到 6 年前
        1
  •  3
  •   7stud    4 年前

    你有一根绳子给你的孩子 dtr_date dtr_日期 :utc_datetime 输入,所以EXTO要求您传递一个 DateTime 结构。

    iex(1)> date_string = "2018-12-30T16:00:00.000Z"             
    "2018-12-30T16:00:00.000Z"
    
    iex(2)> {:ok, dt_struct, utc_offset} = DateTime.from_iso8601(date_string)
    {:ok, #DateTime<2018-12-30 16:00:00.000Z>, 0}
    
    iex(3)> dt_struct
    #DateTime<2018-12-30 16:00:00.000Z>
    

    请看这里:

    Phoenix/Ecto - converting ISO string into utc_datetime primitive type


    cast() 将数据转换为适合您的类型。下面是一个例子:

    lib/
        myapp/
             edtr_api/
                     edtr.ex
                     edtr_api.ex
        myapp_web/
     
    

    edtr.ex:

    defmodule Myapp.EdtrApi.Edtr do
    
      use Ecto.Schema
      import Ecto.Changeset
      alias Myapp.EdtrApi.Edtr
    
      schema "edtrs" do
        field :dtr_date, :utc_datetime, null: false
        field :user_id, :string
    
        timestamps()
      end
    
      def create_changesets(edtr_data) do
        Enum.map(edtr_data, fn data ->
          %Edtr{}
          |> cast(data, [:dtr_date, :user_id])
          |> validate_required([:dtr_date, :user_id])
          |> validate_length(:user_id, min: 10, max: 100)
        end)
      end
    
    end
    

    :

    defmodule Myapp.EdtrApi do
      alias Myapp.EdtrApi.Edtr
      alias Myapp.Repo
      
      def get_data() do 
        [
          %{
              "dtr_date" => "2018-12-29T16:00:00.000Z",
              "user_id" => "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
          },
          %{
              "dtr_date" => "2018-12-30T16:00:00.000Z",
          },
        ]
      end
    
      def insert_edtrs() do
        changesets = Edtr.create_changesets(get_data())
        Enum.map(changesets, fn changeset -> Repo.insert(changeset) end) 
      end
    
      def all() do
        Repo.all(Edtr)
      end
    
    end
    

    然后,您需要创建一个迁移文件:

    ~/phoenix_apps/myapp$ mix ecto.gen.migration create_edtrs
    

    :

    defmodule Myapp.Repo.Migrations.CreateEdtrs do
      use Ecto.Migration
    
      def change do
        create table(:edtrs) do
          add :dtr_date, :utc_datetime, null: false
          add :user_id, :string
    
          timestamps()
        end
    
      end
    end
    

    然后执行迁移以在数据库中创建表:

     ~/phoenix_apps/myapp$ mix ecto.migrate
    

    $ iex -S mix
    Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
    Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
    
    iex(1)> alias Myapp.EdtrApi        
    Myapp.EdtrApi
    
    iex(2)> alias Myapp.EdtrApi.Edtr   
    Myapp.EdtrApi.Edtr
    
    iex(3)> Myapp.Repo.delete_all(Edtr)
    [debug] QUERY OK source="edtrs" db=1.0ms decode=1.7ms queue=0.9ms
    DELETE FROM "edtrs" AS e0 []
    {0, nil}
    
    iex(4)> EdtrApi.insert_edtrs()                  
    [debug] QUERY OK db=7.4ms queue=2.1ms
    INSERT INTO "edtrs" ("dtr_date","user_id","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id" [#DateTime<2018-12-29 16:00:00Z>, "8189f04b-e3d7-4d17-8df2-fedbeb0399b1", ~N[2018-12-11 09:11:18], ~N[2018-12-11 09:11:18]]
    [debug] QUERY OK db=2.3ms queue=1.0ms
    INSERT INTO "edtrs" ("dtr_date","user_id","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id" [#DateTime<2018-12-30 16:00:00Z>, "8189f04b-e3d7-4d17-8df2-fedbeb0399b1", ~N[2018-12-11 09:11:18], ~N[2018-12-11 09:11:18]]
    [
      ok: %Myapp.EdtrApi.Edtr{
        __meta__: #Ecto.Schema.Metadata<:loaded, "edtrs">,
        dtr_date: #DateTime<2018-12-29 16:00:00Z>,
        id: 1,
        inserted_at: ~N[2018-12-11 09:11:18],
        updated_at: ~N[2018-12-11 09:11:18],
        user_id: "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
      },
      ok: %Myapp.EdtrApi.Edtr{
        __meta__: #Ecto.Schema.Metadata<:loaded, "edtrs">,
        dtr_date: #DateTime<2018-12-30 16:00:00Z>,
        id: 2,
        inserted_at: ~N[2018-12-11 09:11:18],
        updated_at: ~N[2018-12-11 09:11:18],
        user_id: "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
      }
    ]
    
    iex(5)> 
    

    Edtr structs 返回的日期字符串已转换为DateTime结构。使命感 这就是为什么。

    好的,现在让我们删除一个 user_id

      def get_edtrs() do 
        [
          %{
              "dtr_date" => "2018-12-29T16:00:00.000Z",
              "user_id" => "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
          },
          %{
              "dtr_date" => "2018-12-30T16:00:00.000Z",
          },
        ]
      end
    

    ~/phoenix_apps/myapp$ iex -S mix
    Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
    Compiling 1 file (.ex)
    Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
    
    iex(1)> alias Myapp.EdtrApi.Edtr   
    Myapp.EdtrApi.Edtr
    
    iex(2)> EdtrApi.insert_edtrs()     
    [debug] QUERY OK db=4.4ms decode=2.9ms queue=1.5ms
    INSERT INTO "edtrs" ("dtr_date","user_id","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id" [#DateTime<2018-12-29 16:00:00Z>, "8189f04b-e3d7-4d17-8df2-fedbeb0399b1", ~N[2018-12-11 09:12:17], ~N[2018-12-11 09:12:17]]
    [
      ok: %Myapp.EdtrApi.Edtr{
        __meta__: #Ecto.Schema.Metadata<:loaded, "edtrs">,
        dtr_date: #DateTime<2018-12-29 16:00:00Z>,
        id: 3,
        inserted_at: ~N[2018-12-11 09:12:17],
        updated_at: ~N[2018-12-11 09:12:17],
        user_id: "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
      },
      error: #Ecto.Changeset<
        action: :insert,
        changes: %{dtr_date: #DateTime<2018-12-30 16:00:00Z>},
        errors: [user_id: {"can't be blank", [validation: :required]}],
        data: #Myapp.EdtrApi.Edtr<>,
        valid?: false
      >
    ]
    
    iex(3)> 
    

    如果检查输出的最后一部分,请注意:

    1. 第二次插入返回的是变更集结构,而不是像第一次插入一样的Edtr结构。

    2. error: ... 而不是 ok: ... ,并且变更集包含:

      错误:[用户id:{“不能为空”,[validation::required]}],

    然后,如果列出数据库表中的所有内容:

    iex(4)> EdtrApi.all             
    [debug] QUERY OK source="edtrs" db=2.8ms queue=2.0ms
    SELECT e0."id", e0."dtr_date", e0."user_id", e0."inserted_at", e0."updated_at" FROM "edtrs" AS e0 []
    [
      %Myapp.EdtrApi.Edtr{
        __meta__: #Ecto.Schema.Metadata<:loaded, "edtrs">,
        dtr_date: #DateTime<2018-12-29 16:00:00Z>,
        id: 1,
        inserted_at: ~N[2018-12-11 09:11:18],
        updated_at: ~N[2018-12-11 09:11:18],
        user_id: "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
      },
      %Myapp.EdtrApi.Edtr{
        __meta__: #Ecto.Schema.Metadata<:loaded, "edtrs">,
        dtr_date: #DateTime<2018-12-30 16:00:00Z>,
        id: 2,
        inserted_at: ~N[2018-12-11 09:11:18],
        updated_at: ~N[2018-12-11 09:11:18],
        user_id: "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
      },
      %Myapp.EdtrApi.Edtr{
        __meta__: #Ecto.Schema.Metadata<:loaded, "edtrs">,
        dtr_date: #DateTime<2018-12-29 16:00:00Z>,
        id: 3,
        inserted_at: ~N[2018-12-11 09:12:17],
        updated_at: ~N[2018-12-11 09:12:17],
        user_id: "8189f04b-e3d7-4d17-8df2-fedbeb0399b1"
      }
    ]
    
    iex(5)>
    

    …您可以看到出现错误的变更集没有在数据库中插入任何内容,因为只有三个条目。

        2
  •  1
  •   Aleksei Matiushkin    6 年前

    FWIW,我会把这个放在这里。几天前,我遇到了一个类似的问题,但原因不同。这个答案可能与所述的确切问题无关,但我一直在努力在互联网上寻找答案,所以就让它在这里吧。

    至少对于 MySQL MariaEx 微秒 DateTime 结构。阿法尤,前者不允许。是否要存储的实例 日期时间 MySQL (例如。 DateTime.utc_now()

    DateTime.truncate/2 :seconds 作为第二个论点:

    now = DateTime.truncate(DateTime.utc_now(), :second)
    
    changeset
    |> Ecto.Changeset.put_change(:created_at, now)
    |> ...