如果未找到则查找或插入,如果更改集无效,则返回错误

时间:2016-09-07 05:51:27

标签: elixir phoenix-framework

如果找不到实体,我想找一个实体或插入它。目前我这样做:

my_item = Repo.get_by(MyItem, var1: "some value") || Repo.insert!(MyItem.changeset(%MyItem{}, %{"var1" => var1}))

有没有更好的方法呢?如果更改集无效,我还想返回错误,目前此代码尚未执行此操作。

2 个答案:

答案 0 :(得分:1)

如果要在多个位置使用此类函数,可以在MyApp.Repo中为此定义一个函数(如果不是,只需将此代码复制到要使用它的控制器中)。将以下内容添加到MyApp.Repo中的lib/my_app/repo.ex模块:

def get_or_insert(schema, params) do
  case get_by(schema, params) do
    nil -> insert(schema.changeset(schema.__struct__, params))
    struct -> {:ok, struct}
  end
end

之后,您可以执行MyApp.Repo.get_or_insert(MyItem, %{var1: "some value"})并返回{:ok, %MyItem{...}}{:error, %Ecto.Changeset{}}

演示:

iex(1)> Repo.all Post
[debug] QUERY OK db=1.2ms
SELECT p0."id", p0."title", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 []
[]
iex(2)> Repo.get_or_insert Post, %{title: "foo"}
[debug] QUERY OK db=1.8ms queue=0.1ms
SELECT p0."id", p0."title", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."title" = $1) ["foo"]
[debug] QUERY OK db=8.5ms
INSERT INTO "posts" ("title","inserted_at","updated_at") VALUES ($1,$2,$3) RETURNING "id" ["foo", {{2016, 9, 7}, {10, 6, 52, 0}}, {{2016, 9, 7}, {10, 6, 52, 0}}]
{:ok,
 %MyApp.Post{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, id: 1,
  inserted_at: #Ecto.DateTime<2016-09-07 10:06:52>, title: "foo",
  updated_at: #Ecto.DateTime<2016-09-07 10:06:52>}}
iex(3)> Repo.get_or_insert Post, %{title: "foo"}
[debug] QUERY OK db=1.8ms decode=2.6ms
SELECT p0."id", p0."title", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."title" = $1) ["foo"]
{:ok,
 %MyApp.Post{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, id: 1,
  inserted_at: #Ecto.DateTime<2016-09-07 10:06:52>, title: "foo",
  updated_at: #Ecto.DateTime<2016-09-07 10:06:52>}}
iex(4)> Repo.get_or_insert Post, %{title: "bar"}
[debug] QUERY OK db=2.0ms
SELECT p0."id", p0."title", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."title" = $1) ["bar"]
[debug] QUERY OK db=8.0ms
INSERT INTO "posts" ("title","inserted_at","updated_at") VALUES ($1,$2,$3) RETURNING "id" ["bar", {{2016, 9, 7}, {10, 6, 59, 0}}, {{2016, 9, 7}, {10, 6, 59, 0}}]
{:ok,
 %MyApp.Post{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, id: 2,
  inserted_at: #Ecto.DateTime<2016-09-07 10:06:59>, title: "bar",
  updated_at: #Ecto.DateTime<2016-09-07 10:06:59>}}
iex(5)> Repo.get_or_insert Post, %{title: "bar"}
[debug] QUERY OK db=2.2ms
SELECT p0."id", p0."title", p0."inserted_at", p0."updated_at" FROM "posts" AS p0 WHERE (p0."title" = $1) ["bar"]
{:ok,
 %MyApp.Post{__meta__: #Ecto.Schema.Metadata<:loaded, "posts">, id: 2,
  inserted_at: #Ecto.DateTime<2016-09-07 10:06:59>, title: "bar",
  updated_at: #Ecto.DateTime<2016-09-07 10:06:59>}}

答案 1 :(得分:0)

试试这个:

item = case Repo.get_by(MyItem, var1: "some value") do
         nil -> insert_item("some_value")
         item -> item
end

插入一些值:

 defp insert_item(params) do
    case Repo.insert(MyItem.changeset(%MyItem{}, %{"var1" => params})) do
      {:ok, item} -> item
      {:error, changeset} -> IO.inspect changeset.errors
    end
  end