如果找不到实体,我想找一个实体或插入它。目前我这样做:
my_item = Repo.get_by(MyItem, var1: "some value") || Repo.insert!(MyItem.changeset(%MyItem{}, %{"var1" => var1}))
有没有更好的方法呢?如果更改集无效,我还想返回错误,目前此代码尚未执行此操作。
答案 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