過去兩天我們分別介紹了Django與Laravel的console模式與基礎ORM操作
今天我們回過頭講解Phoenix的部分
首先,進入介面的指令如下:
$ iex -S mix
Erlang/OTP 20 [erts-9.0.5] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:10] [hipe] [kernel-poll:false] [dtrace]
Interactive Elixir (1.5.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)>
為了後續操作方便,我們會先對想要操作的Model取個別名
iex(1)> alias Hello.User
Hello.User
這樣接下來就可以直接使用User
來試著新增一個空的user
iex(2)> changeset = User.changeset(%User{}, %{})
#Ecto.Changeset<action: nil, changes: %{},
errors: [name: {"can't be blank", [validation: :required]},
email: {"can't be blank", [validation: :required]}], data: #Hello.User<>,
valid?: false>
會得到提示:name
與email
不可為空
驗證是設定在User Model的changeset當中
接著我們把必填欄位補上
iex> params = %{name: "Joe Example", email: "joe@example.com"}
iex> changeset = User.changeset(%User{}, params)
#Ecto.Changeset<action: nil,
changes: %{email: "joe@example.com", name: "Joe Example"}, errors: [],
data: #Hello.User<>, valid?: true>
其實回傳值當中已經可以觀察到valid?: true
但我們依然可以用驗證的方法確認是否通過驗證
iex> changeset.valid?
true
但是到目前為止
這個changeset只存在記憶體當中
我們接下來要把它存入資料庫
iex> alias Hello.{Repo, User}
iex> Repo.insert(changeset)
[debug] QUERY OK db=2.0ms
INSERT INTO "users" ("email","name","inserted_at","updated_at") VALUES ($1,$2,$3,$4) RETURNING "id" ["joe123@example.com", "Joe Example", {{2017, 12, 18}, {9, 11, 4, 672407}}, {{2017, 12, 18}, {9, 11, 4, 672420}}]
{:ok,
%Hello.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
email: "joe123@example.com", id: 2,
inserted_at: ~N[2017-12-18 09:11:04.672407], name: "Joe Example",
updated_at: ~N[2017-12-18 09:11:04.672420]}}
這樣就可以把剛剛的changeset存進去
你可以觀察他自動產生的SQL字串,基本上就是一般的SQL insert
包含了預設的時間戳記
也可以直接把user 欄位資料寫在insert內
這個時候不會檢查必填
iex> Repo.insert(%User{email: "user1@example.com"})
所以這樣依然會新增成功
來檢查一下剛剛新增的內容:
iex> Repo.all(User)
[debug] QUERY OK source="users" db=1.6ms
SELECT u0."id", u0."email", u0."name", u0."inserted_at", u0."updated_at" FROM "users" AS u0 []
[%Hello.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
email: "user1@example.com", id: 1,
inserted_at: ~N[2017-12-18 09:10:01.857415], name: nil,
updated_at: ~N[2017-12-18 09:10:01.859647]},
%Hello.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
email: "joe123@example.com", id: 2,
inserted_at: ~N[2017-12-18 09:11:04.672407], name: "Joe Example",
updated_at: ~N[2017-12-18 09:11:04.672420]}]
可以看到剛剛新增的兩筆資料
假如我們不需要全部的欄位,只需要Email
iex> import Ecto.Query
iex> Repo.all(from u in User, select: u.email)
["user1@example.com", "joe123@example.com"]
會以array的方式回傳
括號內類似SQL的語法稱為DSL
實務上,查詢會另外寫
iex> query = from u in User, select: u.name
iex> Repo.all(query)
[nil, "Joe Example"]
query
可以疊加重組,自由度相當高
iex> query = from u in query
假如只需要取第一個寫入的資料
iex> query = from u in User
iex> Repo.one(first(query, :inserted_at))
[debug] QUERY OK source="users" db=1.7ms
SELECT u0."id", u0."email", u0."name", u0."inserted_at", u0."updated_at" FROM "users" AS u0 ORDER BY u0."inserted_at" LIMIT 1 []
%Hello.User{__meta__: #Ecto.Schema.Metadata<:loaded, "users">,
email: "user1@example.com", id: 1, inserted_at: ~N[2017-12-18 09:10:01.857415],
name: nil, updated_at: ~N[2017-12-18 09:10:01.859647]}
按照Elixir的語法,也可以改寫如下
iex> query |> first(:inserted_at) |> Repo.one
參考資料:
https://github.com/mydearxym/phoenix-doc-in-chinese/blob/master/H_ecto%E6%A8%A1%E5%9E%8B.md
https://hexdocs.pm/ecto/Ecto.Query.html