Ecto模式参考Skill ecto-patterns

Ecto模式是Elixir语言中数据库操作的库,提供模式、查询、变更集和迁移的最佳实践参考,帮助开发者避免常见错误并提升代码质量。关键词:Ecto、Elixir、数据库、模式、查询、变更集、迁移、后端开发、最佳实践。

后端开发 0 次安装 0 次浏览 更新于 3/11/2026

name: ecto-patterns description: Ecto模式用于模式、查询、变更集和迁移。在编写数据库代码时加载。 user-invocable: false

Ecto模式参考

用于处理Ecto模式、查询和迁移的参考。

铁律 — 绝不违反

  1. 变更集用于外部数据 — 使用 cast/4 处理用户/API输入,change/2put_change/3 处理内部可信数据
  2. 永远不要用 :float 表示金钱 — 始终使用 :decimal:integer(以分为单位)
  3. 不要使用Rails风格的多态关联 — 它们破坏外键约束;使用多个可空外键或单独的连接表
  4. 始终在查询中固定值u.name == ^user_input 是安全的,字符串插值会导致SQL注入
  5. 预加载集合,而非单个对象 — 在循环中预加载会导致N+1查询问题
  6. 约束优于验证以防止竞态条件 — 验证提供快速反馈,约束提供数据库级别的安全性
  7. has_many 使用单独查询,belongs_to 使用JOIN — 避免行乘法
  8. 不要使用隐式交叉连接from(a in A, b in B) 没有 on: 会导致笛卡尔积
  9. cast_assoc 前对共享数据去重 — 当多个父级共享子数据时,在构建变更集前对子记录去重。去重仅在单个变更集内有效

快速模式模板

defmodule MyApp.Context.Entity do
  use Ecto.Schema
  import Ecto.Changeset

  @primary_key {:id, :binary_id, autogenerate: true}
  @foreign_key_type :binary_id

  schema "entities" do
    field :name, :string
    field :status, Ecto.Enum, values: [:draft, :active, :archived]
    field :amount_cents, :integer  # 永远不要用:float表示金钱!
    belongs_to :user, MyApp.Accounts.User
    timestamps(type: :utc_datetime_usec)
  end

  def changeset(entity, attrs) do
    entity
    |> cast(attrs, [:name, :status, :amount_cents])
    |> validate_required([:name])
    |> foreign_key_constraint(:user_id)
  end
end

快速决策

cast vs put_change vs change

函数 使用时机
cast/4 外部数据(用户输入,API)
put_change/3 内部可信数据(时间戳,计算值)
change/2 来自现有结构的内部数据

预加载策略

关系 策略
belongs_to JOIN(单个查询)
has_many 单独查询(避免行乘法)

常见反模式

错误 正确
field :amount, :float field :amount_cents, :integer
"SELECT * WHERE name = '#{name}'" from(u in User, where: u.name == ^name)
Repo.all(User) |> Enum.filter(& &1.active) from(u in User, where: u.active)
在循环中预加载 Repo.preload(posts, :comments)
Repo.get!(User, user_id) 使用用户输入 Repo.get(User, id) + 处理nil

参考

详细模式请参阅:

  • references/changesets.md - cast vs put_change,自定义验证,prepare_changes
  • references/queries.md - 可组合查询,动态查询,子查询,预加载
  • references/migrations.md - 安全迁移,并发索引,NOT NULL
  • references/transactions.md - Repo.transact,Ecto.Multi,upserts