基礎

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!