Introdução ao Ecto com Elixir: Configuração e Operações Básicas
Durante minha jornada de aprendizado em Elixir, descobri o Ecto, uma poderosa camada de abstração para bancos de dados e gerador de consultas que permite interagir com bancos SQL de forma intuitiva. Embora frequentemente comparado a ORMs como o Entity Framework Core ou o ActiveRecord do Ruby on Rails, o Ecto se diferencia por não rastrear automaticamente estados de entidades, exigindo que os desenvolvedores gerenciem mudanças de forma explícita. Este artigo explora conceitos fundamentais do Ecto, incluindo repositórios, schemas, migrações e operações CRUD. Para recursos avançados, consulte a documentação oficial do Ecto.
O que é o Ecto?
O Ecto é uma camada de abstração para bancos de dados projetada para trabalhar com bancos relacionais como PostgreSQL e MySQL. Ele oferece:
- Mapeamento de tabelas para structs (via schemas).
- Geração de consultas com sintaxe segura usando a sintaxe do Elixir.
- Validação de dados antes da persistência (via changesets).
- Gerenciamento de migrações com controle de versão.
Por que o Ecto não é um ORM tradicional?
O Ecto evita armadilhas comuns de ORMs tradicionais:
- Sem rastreamento automático de estado: Diferente de ORMs, o Ecto não rastreia estados de entidades (ex: campos modificados).
- Fluxo de dados explícito: Desenvolvedores devem passar dados manualmente por changesets antes da persistência.
- Alinhamento com o paradigma funcional: O Ecto segue o modelo de programação funcional do Elixir, evitando o "impedance mismatch" de mapeamento objeto-relacional.
Requisitos
- Elixir 1.18+ (ajuste para versões anteriores, se necessário)
- Adicione as dependências em mix.exs:
{:ecto_sql, "~> 3.0"},  # Ecto  
{:postgrex, ">= 0.0.0"} # Driver para PostgreSQL  
Configuração do Repositório
Um repositório (ou repo) é a interface do Ecto com o banco de dados, semelhante ao DbContext do Entity Framework.  
Configuração Manual
- Defina um módulo de repositório:
defmodule Friends.Repo do  
  use Ecto.Repo,  
    otp_app: :friend,  
    adapter: Ecto.Adapters.Postgres  
end  
- Configure em config/config.exs:
config :friends, Friends.Repo,  
  database: "friends",  
  username: "user",  
  password: "pass",  
  hostname: "localhost"  
Configuração Automática via Mix
Execute:
mix ecto.gen.repo -r Friends.Repo  
Executando o Ecto no Início
Adicione o repositório ao supervisor da aplicação em lib/<app_name>/application.ex:
def start(_type, _args) do  
  children = [Friends.Repo]  
  ...  
end  
Atualize config/config.exs:
config :friends, ecto_repos: [Friends.Repo]  
Criando um Schema
Um schema mapeia uma tabela do banco para uma struct do Elixir. Exemplo de schema Person:
defmodule Friends.Person do  
  use Ecto.Schema  
  import Ecto.Changeset  
  schema "people" do  
    field :first_name, :string  
    field :last_name, :string  
    field :age, :integer  
  end  
  def changeset(person, params \\ %{}) do  
    person  
    |> cast(params, [:first_name, :last_name, :age])  
    |> validate_required([:first_name, :last_name])  
  end  
end  
Migrações
Migrações definem alterações incrementais no esquema do banco.
Migração Manual
Crie um arquivo em priv/repo/migrations/<datetime>_create_people.exs:
defmodule Friends.Repo.Migrations.CreatePeople do  
  use Ecto.Migration  
  def change do  
    create table(:people) do  
      add :first_name, :string  
      add :last_name, :string  
      add :age, :integer  
    end  
  end  
end  
Migração Automática via Mix
Execute:
mix ecto.gen.migration create_people  
Este comando cria um arquivo vazio para edição.
Executando Migrações
mix ecto.create   # Cria o banco de dados  
mix ecto.migrate # Executa as migrações  
Operações CRUD
Create (Criar)
Insira um novo registro:
person = %Friends.Person{first_name: "Alice", last_name: "Smith", age: 30}  
{:ok, inserted_person} = Friends.Repo.insert(person)  
Com validação:
changeset = Friends.Person.changeset(%Friends.Person{}, %{first_name: "Alice"})  
case Friends.Repo.insert(changeset) do  
  {:ok, person} -> # Sucesso  
  {:error, changeset} -> # Trate erros  
end  
Read (Ler)
Busque registros:
# Por ID  
Friends.Repo.get(Friends.Person, 1)  
# Primeiro registro  
Friends.Repo.one(from p in Friends.Person, order_by: [asc: p.id], limit: 1)  
# Todos os registros que atendem a uma condição  
Friends.Repo.all(from p in Friends.Person, where: like(p.first_name, "A%"))  
Update (Atualizar)
Atualize um registro existente:
person = Friends.Repo.get!(Friends.Person, 1)  
changeset = Friends.Person.changeset(person, %{age: 31})  
Friends.Repo.update(changeset)  
Delete (Excluir)
Exclua um registro:
person = Friends.Repo.get!(Friends.Person, 1)  
Friends.Repo.delete(person)  
Conclusão
O Ecto equilibra abstração e controle, oferecendo:
- Consultas com segurança de tipos: Prevenção de erros em tempo de compilação.
- Fluxos explícitos: Changesets garantem validação antes da persistência.
- Suporte da comunidade: Amplamente adotado no ecossistema Elixir.
Embora não seja um ORM tradicional, o design funcional do Ecto evita abstrações problemáticas comuns em mapeadores objeto-relacionais. Para padrões avançados (ex: associações), explore suporte a has_many, belongs_to e many_to_many.  
 
 
              
 
    
Top comments (0)