Do you want to pick up from where you left of?
Take me there

基礎

Ecto 是一個官方 Elixir 專案,提供資料庫封裝 (wrapper) 和整合查詢語言。通過 Ecto,能夠建立遷移 (migration)、定義結構描述 (schema)、插入 (insert) 和更新記錄 (update) 並查詢 (query)。

Table of Contents

轉接器

Ecto 經由使用轉接器支援不同的資料庫,幾個轉接器的範例如下:

在本課程中,將會設定 Ecto 來使用 PostgreSQL 轉接器。

入門

在本課程中,將涵蓋 Ecto 的三個部分:

首先,將使用 supervision 樹建立一個應用程式。

mix new friends --sup
cd friends

將 ecto 和 postgrex 套件相依關係添加到 mix.exs 檔案中。

  defp deps do
    [
      {:ecto_sql, "~> 3.2"},
      {:postgrex, "~> 0.15"}
    ]
  end

使用以下指令擷取相依關係

mix deps.get

建立存放庫 (Repository)

Ecto 中的存放庫映射到資料儲存,例如 Postgres 資料庫。 所有與資料庫的交流都將使用此存放庫完成。

通過執行以下指令設置存放庫:

mix ecto.gen.repo -r Friends.Repo

這會在 config/config.exs 中建立連接到包含要使用轉接器的資料庫的所需配置。 這是 Friends 應用程式的配置檔案

config :friends, Friends.Repo,
  database: "friends_repo",
  username: "postgres",
  password: "",
  hostname: "localhost"

這將配置 Ecto 如何連接到資料庫。

同時它還在 lib/friends/repo.ex 中建立了一個 Friends.Repo 模組。

defmodule Friends.Repo do
  use Ecto.Repo, 
    otp_app: :friends,
    adapter: Ecto.Adapters.Postgres
end

我們將使用 Friends.Repo 模組來查詢資料庫。同時也告訴模組在 :friends 應用程式中尋找其資料庫配置資訊。並且選擇了 Ecto.Adapters.Postgres 轉接器。

接下來,將在 lib/friends/application.ex 中的應用程式 supervision 樹中將 Friends.Repo 設定為 supervisor。 這將在應用程式啟動時啟動 Ecto 處理程序。

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      Friends.Repo,
    ]

  ...

之後還需要在 config/config.exs 檔案中加入下面這一行:

config :friends, ecto_repos: [Friends.Repo]

這將允許應用程式從命令列執行 ecto mix 指令。

現在儲存庫已經配置完成! 可以使用以下指令在 postgres 中建立資料庫:

mix ecto.create

Ecto 將使用 config/config.exs 檔案中的資訊來確定如何連接到 Postgres 以及如何命名資料庫。

如果收到任何錯誤訊息,請確保配置的資料正確並且 postgres 實例有在運行。

遷移 (Migrations)

為了在 postgres 資料庫中建立和修改表格,Ecto 為此提供了遷移。 每個遷移都描述了要對資料庫執行的一組操作,比如要建立或更新的表格。

由於資料庫還未有任何表格,將需要建立一個遷移來加入這些表格。 在 Ecto 中約定 (convention) 是命名表格為複數,因此對於應用程式,需要一個 people 表格,將從那裡開始使用遷移。

建立遷移的最佳方法是執行 mix ecto.gen.migration <name>,所以在範例中將使用:

mix ecto.gen.migration create_people

這會在 priv/repo/migrations 資料夾內生成一個檔案名中含有時間戳記的新檔案。 如果導引到該目錄並開啟遷移,應該會看到如下內容:

defmodule Friends.Repo.Migrations.CreatePeople do
  use Ecto.Migration

  def change do

  end
end

從修改 change/0 函數著手以建立一個帶有 nameage 的新 people 表格:

defmodule Friends.Repo.Migrations.CreatePeople do
  use Ecto.Migration

  def change do
    create table(:people) do
      add :name, :string, null: false
      add :age, :integer, default: 0
    end
  end
end

可以看到在上面同時還定義了欄 (column) 的資料型別。 此外,還包括 null: falsedefault: 0 作為選項。

現在跳到 shell 並執行遷移:

mix ecto.migrate

結構描述 (Schemas)

目前已經建立了初始表格,現在需要告訴 Ecto 更多關於如何通過結構描述進行操作的部分。 結構描述是定義映射到底層資料庫表格欄位的模組。

雖然 Ecto 偏愛命名資料格表格為複數,不過結構描述通常是單數的,因此將與表格一起建立一個 Person 結構描述。

現在於 lib/friends/person.ex 中建立所要的新結構描述:

defmodule Friends.Person do
  use Ecto.Schema

  schema "people" do
    field :name, :string
    field :age, :integer, default: 0
  end
end

在這裡可以看到 Friends.Person 模組告訴 Ecto 這個結構描述與 people 表格有關,我們有兩欄 (column): name 是一字串,而 age,一個預設為 0 的整數。

現在通過開啟 iex 並建立一個新 person 來瞧瞧結構描述:

iex> %Friends.Person{}
%Friends.Person{age: 0, name: nil}

正如預期的那樣,得到一個新的 Person 並使用了 age 的預設值。 現在來建立一個 “真正的” person:

iex> person = %Friends.Person{name: "Tom", age: 11}
%Friends.Person{age: 11, name: "Tom"}

由於結構描述只是結構體(structs),所以能夠像以前習慣那樣與資料進行互動:

iex> person.name
"Tom"
iex> Map.get(person, :name)
"Tom"
iex> %{name: name} = person
%Friends.Person{age: 11, name: "Tom"}
iex> name
"Tom"

同樣地,可以更新結構描述就像在 Elixir 的任何其他映射或結構體上做的一樣:

iex> %{person | age: 18}
%Friends.Person{age: 18, name: "Tom"}
iex> Map.put(person, :name, "Jerry")
%Friends.Person{age: 11, name: "Jerry"}

在關於變更集的下一課程中,將了解如何驗證資料變更以及如何將它們保存到資料庫中。

Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!