基礎

翻譯內文可能已過時。
自最近更新後,原始課程已執行多次修補 (patches)。

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

目錄

轉接器

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

  • PostgreSQL
  • MySQL
  • SQLite

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

入門

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

  • 存放庫 — 提供資料庫的界面,包括連線部分 (connection)
  • 遷移 — 一種建立、修改和刪除資料庫表格和索引的機制
  • 結構描述 — 表示資料庫表格項目的專用結構

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

$ mix new friends --sup
$ cd friends

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

  defp deps do
    [
      {:ecto, "~> 2.0"},
      {:postgrex, "~> 0.11"}
    ]
  end

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

$ mix deps.get

建立存放庫 (Repository)

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

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

$ mix ecto.gen.repo -r Example.Repo

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

config :friends, Example.Repo,
  adapter: Ecto.Adapters.Postgres,
  database: "friends_repo",
  username: "postgres",
  password: "",
  hostname: "localhost"

這將配置 Ecto 如何連接到資料庫。 注意到是如何選擇 Ecto.Adapters.Postgres 轉接器。

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

defmodule Example.Repo do
  use Ecto.Repo, otp_app: :friends
end

我們將使用 Example.Repo 模組來查詢資料庫。同時也告訴模組在 :friends 應用程式中尋找其資料庫配置資訊。

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

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

  ...

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

config :friends, ecto_repos: [Example.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 Example.Repo.Migrations.CreatePeople do
  use Ecto.Migration

  def change do

  end
end

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

defmodule Example.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 Example.Person do
  use Ecto.Schema

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

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

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

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

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

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

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

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

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

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

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