O que Todo Dev Deve Saber sobre Camada Model: Repositórios e Mapeamento de Dados Já leu

Compreendendo a Camada Model: Fundamentos A camada Model é o coração de qualquer aplicação bem arquitetada. Ela representa os dados da sua aplicação e as regras de negócio associadas a eles. Quando falamos em repositórios e mapeamento de dados, estamos trabalhando com dois conceitos complementares que separam a lógica de negócio do acesso aos dados. O Model não deve conhecer como os dados são persistidos; essa responsabilidade fica com o repositório. Já o mapeamento transforma dados brutos do banco em objetos estruturados que sua aplicação compreende. Pense em um e-commerce: a classe (seu Model) contém informações como nome, preço e descrição. Mas como esses dados chegam do banco de dados? Por meio do repositório, que implementa a interface entre a aplicação e a persistência. Esse padrão garante que sua aplicação seja flexível: você pode trocar de banco de dados sem mexer na lógica de negócio. Repositórios: O Padrão que Organiza o Acesso a Dados O que é um Repositório? Um

Compreendendo a Camada Model: Fundamentos

A camada Model é o coração de qualquer aplicação bem arquitetada. Ela representa os dados da sua aplicação e as regras de negócio associadas a eles. Quando falamos em repositórios e mapeamento de dados, estamos trabalhando com dois conceitos complementares que separam a lógica de negócio do acesso aos dados. O Model não deve conhecer como os dados são persistidos; essa responsabilidade fica com o repositório. Já o mapeamento transforma dados brutos do banco em objetos estruturados que sua aplicação compreende.

Pense em um e-commerce: a classe Produto (seu Model) contém informações como nome, preço e descrição. Mas como esses dados chegam do banco de dados? Por meio do repositório, que implementa a interface entre a aplicação e a persistência. Esse padrão garante que sua aplicação seja flexível: você pode trocar de banco de dados sem mexer na lógica de negócio.

Repositórios: O Padrão que Organiza o Acesso a Dados

O que é um Repositório?

Um repositório é uma abstração que encapsula a lógica de acesso aos dados. Em vez de sua aplicação conversar diretamente com o banco, ela conversa com o repositório, que por sua vez gerencia todas as operações (criar, ler, atualizar, deletar). Isso permite que você mude de tecnologia de persistência sem alterar o código que usa esses dados.

# Exemplo em Python com SQLAlchemy
from abc import ABC, abstractmethod
from typing import List, Optional

class RepositorioProduto(ABC):
    @abstractmethod
    def buscar_por_id(self, id: int) -> Optional['Produto']:
        pass

    @abstractmethod
    def listar_todos(self) -> List['Produto']:
        pass

    @abstractmethod
    def salvar(self, produto: 'Produto') -> 'Produto':
        pass

    @abstractmethod
    def deletar(self, id: int) -> bool:
        pass

Implementação Concreta

Aqui está uma implementação real que trabalha com um banco SQL:

from sqlalchemy.orm import Session
from models import Produto

class RepositorioProdutoSQL(RepositorioProduto):
    def __init__(self, session: Session):
        self.session = session

    def buscar_por_id(self, id: int) -> Optional[Produto]:
        return self.session.query(Produto).filter(Produto.id == id).first()

    def listar_todos(self) -> List[Produto]:
        return self.session.query(Produto).all()

    def salvar(self, produto: Produto) -> Produto:
        self.session.add(produto)
        self.session.commit()
        return produto

    def deletar(self, id: int) -> bool:
        produto = self.buscar_por_id(id)
        if produto:
            self.session.delete(produto)
            self.session.commit()
            return True
        return False

A vantagem é clara: sua camada de serviço não sabe que está usando SQL. Se amanhã precisar usar MongoDB, você cria um novo repositório sem alterar a lógica de negócio.

Mapeamento de Dados: Do Banco para Objetos

O Desafio da Representação

O mapeamento transforma dados do banco (colunas, tipos primitivos) em objetos estruturados do seu código. Sem um mapeamento claro, você acaba com código confuso que mistura consultas SQL com lógica de negócio. Existem duas abordagens principais: ORM (Object-Relational Mapping) e mapeamento manual.

Usando ORM (SQLAlchemy)

from sqlalchemy import Column, Integer, String, Float, DateTime
from sqlalchemy.ext.declarative import declarative_base
from datetime import datetime

Base = declarative_base()

class Produto(Base):
    __tablename__ = 'produtos'

    id = Column(Integer, primary_key=True)
    nome = Column(String(100), nullable=False)
    preco = Column(Float, nullable=False)
    descricao = Column(String(500))
    criado_em = Column(DateTime, default=datetime.utcnow)

    def aplicar_desconto(self, percentual: float) -> float:
        """Lógica de negócio: cálculo de desconto"""
        return self.preco * (1 - percentual / 100)

    def __repr__(self):
        return f"<Produto(id={self.id}, nome='{self.nome}', preco={self.preco})>"

A ORM cuida automaticamente do mapeamento entre colunas e atributos. Quando você faz produto.nome = "Novo Nome", a ORM sabe que precisa atualizar a coluna correspondente.

Mapeamento Manual com DTOs

Para casos mais complexos ou APIs REST, é comum usar Data Transfer Objects (DTOs) para separar a representação interna da externa:

from dataclasses import dataclass
from datetime import datetime

@dataclass
class ProdutoDTO:
    """Representação para API - não conhece detalhes do banco"""
    id: int
    nome: str
    preco: float
    descricao: str
    criado_em: datetime

def mapear_para_dto(produto: Produto) -> ProdutoDTO:
    """Transforma Model em DTO"""
    return ProdutoDTO(
        id=produto.id,
        nome=produto.nome,
        preco=produto.preco,
        descricao=produto.descricao,
        criado_em=produto.criado_em
    )

def mapear_para_model(dto: ProdutoDTO) -> Produto:
    """Transforma DTO em Model"""
    produto = Produto()
    produto.id = dto.id
    produto.nome = dto.nome
    produto.preco = dto.preco
    produto.descricao = dto.descricao
    return produto

Essa separação é fundamental quando você quer que a API retorne apenas certos campos ou quando precisa validar dados antes de persistir.

Integrando Tudo: Repositório + Model + Mapeamento

Um Exemplo Prático Completo

class Servicoproduto:
    """Camada de serviço que usa repositório e mapeamento"""

    def __init__(self, repositorio: RepositorioProduto):
        self.repositorio = repositorio

    def criar_produto(self, dto: ProdutoDTO) -> ProdutoDTO:
        produto = mapear_para_model(dto)
        produto_salvo = self.repositorio.salvar(produto)
        return mapear_para_dto(produto_salvo)

    def obter_produto(self, id: int) -> Optional[ProdutoDTO]:
        produto = self.repositorio.buscar_por_id(id)
        return mapear_para_dto(produto) if produto else None

    def aplicar_desconto_e_salvar(self, id: int, percentual: float) -> ProdutoDTO:
        produto = self.repositorio.buscar_por_id(id)
        if not produto:
            raise ValueError(f"Produto {id} não encontrado")

        novo_preco = produto.aplicar_desconto(percentual)
        produto.preco = novo_preco
        self.repositorio.salvar(produto)
        return mapear_para_dto(produto)

Veja como a lógica de negócio fica clara: não há SQL, não há detalhes de banco de dados. A camada de serviço trabalha com abstrações (repositório) e dados estruturados (DTOs e Models).

Conclusão

Os três pontos-chave que você deve lembrar sempre: Primeiro, o repositório é sua barreira contra o banco de dados — ele encapsula como você recupera e persiste dados, permitindo mudanças futuras sem impacto na lógica. Segundo, o mapeamento (seja via ORM ou manual com DTOs) transforma dados brutos em objetos significativos para seu negócio, evitando que strings genéricas inundem seu código. Terceiro, separar Model (o quê), Repositório (como buscar) e Serviço (o quê fazer) cria uma arquitetura que escala e que outros desenvolvedores conseguem entender e modificar sem medo.

Domine esses conceitos e sua aplicação terá uma base sólida para crescer.

Referências


Artigos relacionados