📐 CAPÍTULO 05: MODELO RELACIONAL E MODELAGEM CONCEITUAL
🎯 Objetivos de Aprendizagem
Ao final deste capítulo (estimativa: 2 horas de estudo autoguiado), você será capaz de:
- 🔹 Compreender os fundamentos do Modelo Entidade-Relacionamento (MER) de Peter Chen e do Modelo Relacional de Edgar Codd.
- 🔹 Identificar Entidades Fortes, Entidades Fracas, Atributos Simples, Compostos e Multivalorados.
- 🔹 Modelar cardinalidades fundamentais: Um para Um (1:1), Um para Muitos (1:N) e Muitos para Muitos (N:N).
- 🔹 Construir diagramas relacionais e conceituais utilizando Mermaid e Draw.io.
O "coração" da engenharia de dados moderna é baseado na matemática. Criado na década de 70 por Edgar F. Codd (cientista da IBM), o Modelo Relacional revolucionou o mundo ao organizar informações de forma previsível e segura. 🛡️🧩
🏢 O Cenário Prático (Seu Desafio)
Você assumiu a área de Arquitetura de Dados da TecProExpress. A equipe de negócios enviou um documento textual gigante descrevendo como eles querem que o sistema funcione. Os programadores não sabem por onde começar a codificar as tabelas.
"Seu desafio é ser a ponte de comunicação. Você precisa traduzir as necessidades do negócio (Mundo Real) em um diagrama visual (Mini-mundo) e depois em código SQL estruturado."
🧠 Fundamentos: O Dicionário Relacional
No mercado profissional, evitamos termos amadores. Um Arquiteto de Elite domina a nomenclatura técnica.
| Nome Comercial | Nomenclatura Científica | O que representa na prática? |
|---|---|---|
| Tabela | Relação | Estrutura que guarda entidades (ex: cliente). |
| Linha / Registro | Tupla | Uma ocorrência específica (ex: O cliente João). |
| Coluna / Campo | Atributo | Propriedade (ex: nome, cpf). |
| Tipo de Dado | Domínio | Regras de formato permitidas (ex: INT, VARCHAR). |
📊 Anatomia de uma Tabela (Relação)
erDiagram
PRODUTO {
int id_produto PK
string nome
decimal preco
}
🔍 Detalhamento das Regras de Ouro:
- Atomicidade: Cada célula deve conter apenas um único valor indivisível. (Nada de guardar dois telefones na mesma coluna).
- Unicidade: Não existem linhas 100% iguais (garantido pela PK - Primary Key).
- O Valor NULL: Representa ausência de informação. Atenção: NULL não é zero e nem um texto vazio ("").
📖 Exemplo Guiado: Criando o Dicionário (DDL -> DML)
A melhor forma de entender os domínios é aplicando restrições no código.
🛠️ Código do Exemplo
-- PASSO 1: DDL (Definindo Relação, Atributos e Domínios)
CREATE TABLE fornecedor (
id INT PRIMARY KEY,
nome VARCHAR(100) NOT NULL,
status_ativo BOOLEAN
);
-- PASSO 2: DML (Inserindo Tuplas)
INSERT INTO fornecedor (id, nome, status_ativo) VALUES (1, 'TecProExpress', TRUE);
INSERT INTO fornecedor (id, nome, status_ativo) VALUES (2, 'Fornecedor Beta', NULL);
🔍 Detalhamento do Código:
VARCHAR(100): O domínio restringe o tamanho do atributo "nome" a 100 letras.NULL: O segundoINSERTusa NULL porque ainda não sabemos o status do Fornecedor Beta.
📐 O Ciclo de Vida da Modelagem
O processo de traduzir o mundo real para tabelas ocorre em 3 fases:
- 🧠 Modelo Conceitual: Foca na regra de negócio. Desenho em alto nível (Diagrama Entidade-Relacionamento - DER) que o cliente consegue entender.
- ⚙️ Modelo Lógico: Traduz o diagrama para tabelas (com PKs e FKs), mas ainda sem código específico.
- 💻 Modelo Físico: O script de criação (SQL DDL) que roda dentro do SGBD (MySQL/Postgres).
📊 O Fluxo de Abstração
flowchart TD
REAL["🌍 Mundo Real"] --> ABS{"🔍 Abstração"}
ABS --> MINI["🗺️ Modelo Conceitual"]
MINI --> LOG["📐 Modelo Lógico"]
LOG --> FIS["💻 Modelo Físico (SQL)"]
🛠️ Prática Obrigatória: Abstração Inicial
Cenário: A TecProExpress quer modelar seus veículos de frota.
- Identifique as Entidades e Atributos para um veículo.
- Crie a tabela
veiculo_frotausando DDL e insira uma tupla usando DML.
🚀 Script de Seed (Gabarito Físico)
-- DDL
CREATE TABLE veiculo_frota (
id_veiculo INT PRIMARY KEY,
placa VARCHAR(7) NOT NULL,
capacidade_carga_kg DECIMAL(10,2)
);
-- DML
INSERT INTO veiculo_frota (id_veiculo, placa, capacidade_carga_kg) VALUES (101, 'ABC1234', 5000.00);
💻 Ponte Prática: Do SQL Manual ao SQLAlchemy 2.0 ORM
Como traduzir os conceitos matemáticos de Relação (Tabela), Tupla (Linha) e Domínio (Tipo de Dado) para o código Python moderno?
🔴 1. A Abordagem Manual (Dicionários em Memória sem Atomicidade)
No modelo procedural sem ORM, os dados de entidades vivem em dicionários desprotegidos. O desenvolvedor corre o risco de violar a atomicidade ou aceitar tipos inconsistentes:
# ❌ ABORDAGEM PROCEDURAL: Dicionários com tipos inconsistentes e campos soltos
fornecedores_memoria = [
{"id": 1, "nome": "TecProExpress", "status": True},
{"id": 2, "nome": 12345, "status": "ativo"} # ⚠️ Nome como número e status como string!
]
🟢 2. A Abordagem com SQLAlchemy 2.0 (Mapeamento Declarativo Tipado)
Com o SQLAlchemy 2.0, cada Relação é uma classe e cada Atributo possui seu Domínio explicitado com Type Hints:
# ✅ ABORDAGEM MODERNA: Mapeamento Conceitual -> Lógico -> Físico via SQLAlchemy
from sqlalchemy import create_engine, String, Boolean, Integer, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
class Base(DeclarativeBase):
pass
class FornecedorModel(Base):
"""Representa a Relação FORNECEDOR no Modelo Relacional."""
__tablename__ = "fornecedores"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
nome: Mapped[str] = mapped_column(String(100), nullable=False)
status_ativo: Mapped[bool | None] = mapped_column(Boolean, nullable=True) # Aceita NULL
def __repr__(self) -> str:
status_str = "Ativo" if self.status_ativo is True else ("Inativo" if self.status_ativo is False else "Pendente (NULL)")
return f"Fornecedor(id={self.id}, nome='{self.nome}', status={status_str})"
🛠️ Mini-Projeto 05 (BD): Catálogo de Fornecedores e Mapeamento Relacional
Objetivo: Implementar o ciclo completo da modelagem conceitual à persistência física de fornecedores com manipulação de valores NULL.
📋 Pré-requisitos e Instalação
No terminal do seu ambiente virtual (PowerShell ou Bash), instale a biblioteca necessária:
pip install sqlalchemy
💻 Código Completo e Autocontido (miniprojeto_05_dominios.py)
Crie o arquivo miniprojeto_05_dominios.py e insira o código abaixo integralmente:
"""
Mini-Projeto 05: Catálogo de Fornecedores e Mapeamento Relacional
Curso: GTI - Banco de Dados Relacionais e Engenharia de Software
Stack: Python 3.11+ | SQLAlchemy 2.0 | SQLite
"""
import os
from sqlalchemy import create_engine, String, Integer, Boolean, select
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session
# 1. Definição Declarativa do Schema
class Base(DeclarativeBase):
pass
class FornecedorModel(Base):
__tablename__ = "fornecedores"
id: Mapped[int] = mapped_column(Integer, primary_key=True, autoincrement=True)
nome: Mapped[str] = mapped_column(String(100), nullable=False)
status_ativo: Mapped[bool | None] = mapped_column(Boolean, nullable=True) # Aceita NULL
def __repr__(self) -> str:
status_str = "Ativo" if self.status_ativo is True else ("Inativo" if self.status_ativo is False else "Pendente (NULL)")
return f"Fornecedor(id={self.id}, nome='{self.nome}', status={status_str})"
# 2. Ponto de Entrada Executável
if __name__ == "__main__":
DB_FILE = "tecpro_fornecedores.db"
# Reset preventivo para garantir idempotência em testes repetidos
if os.path.exists(DB_FILE):
os.remove(DB_FILE)
engine = create_engine(f"sqlite:///{DB_FILE}", echo=False)
Base.metadata.create_all(bind=engine)
print("📐 MAPEAMENTO RELACIONAL: RELAÇÃO, TUPLAS E ATRIBUTOS")
print("=" * 65)
# 1. Inserindo tuplas relacionais
with Session(engine) as session:
f1 = FornecedorModel(nome="TecProExpress Matriz Logística", status_ativo=True)
f2 = FornecedorModel(nome="Pneus & Cargas Brasil", status_ativo=False)
f3 = FornecedorModel(nome="Novo Fornecedor em Homologação", status_ativo=None) # NULL no banco
session.add_all([f1, f2, f3])
session.commit()
print("✅ 3 Tuplas persistidas com sucesso na relação 'fornecedores'!")
# 2. Consultando e exibindo as tuplas relacionais
print("\n🔍 Consultando catálogo de fornecedores:")
with Session(engine) as session:
stmt = select(FornecedorModel)
for fornecedor in session.scalars(stmt).all():
print(f" 🏢 {fornecedor}")
print("=" * 65)
🚀 Como Executar
Execute o script no terminal:
python miniprojeto_05_dominios.py
🖥️ Saída Esperada no Console
📐 MAPEAMENTO RELACIONAL: RELAÇÃO, TUPLAS E ATRIBUTOS
=================================================================
✅ 3 Tuplas persistidas com sucesso na relação 'fornecedores'!
🔍 Consultando catálogo de fornecedores:
🏢 Fornecedor(id=1, nome='TecProExpress Matriz Logística', status=Ativo)
🏢 Fornecedor(id=2, nome='Pneus & Cargas Brasil', status=Inativo)
🏢 Fornecedor(id=3, nome='Novo Fornecedor em Homologação', status=Pendente (NULL))
=================================================================
💡 Checkpoint de Lógica
Reflexão Profissional: Por que a Modelagem Conceitual é considerada a fase mais crítica de um projeto de software? (Resposta: Porque código SQL mal feito pode ser reescrito rapidamente, mas se a equipe entender a regra de negócio errado no Modelo Conceitual, todo o sistema será construído para resolver o problema errado). 🧠🛡️
🧪 Quiz de Fixação e Autoavaliação — Capítulo 05
🧪 Quiz de Fixação e Autoavaliação — Capítulo 05
1. Quem foi o cientista da computação britânico que formulou o Modelo Relacional de Dados em 1970 nos laboratórios da IBM?
- A) Alan Turing
- B) Edgar Frank Codd (E. F. Codd)
- C) Peter Chen
- D) Linus Torvalds
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: E. F. Codd revolucionou a computação em 1970 com o artigo histórico 'A Relational Model of Data for Large Shared Data Banks', introduzindo tabelas, tuplas e álgebra relacional.
2. Qual cardinalidade existe entre 'Cliente' e 'Pedido' em um sistema de e-commerce tradicional?
- A) 1 : 1 (Um cliente só pode fazer um único pedido na vida).
- B) 1 : N (Um cliente pode fazer muitos pedidos ao longo do tempo, mas cada pedido pertence a exatamente um cliente).
- C) N : N (Um pedido pode pertencer a 50 clientes diferentes ao mesmo tempo).
- D) Nenhuma relação.
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: Relacionamento 1:N clássico: a Chave Primária do Cliente (id_cliente) viaja para a tabela de Pedidos como Chave Estrangeira (id_cliente_fk).
3. No Modelo Entidade-Relacionamento (MER), o que é um 'Atributo Multivalorado' (ex: Telefones de um Fornecedor)?
- A) Um atributo que só aceita números negativos.
- B) Um atributo que pode conter mais de um valor simultâneo para a mesma entidade (ex: um fornecedor com 3 números de telefone diferentes).
- C) Um atributo que guarda o preço em dólares.
- D) A chave primária da tabela.
💡 Ver Resposta e Justificativa
Resposta Correta: B
Justificativa: Atributos multivalorados violam a 1ª Forma Normal no modelo relacional e devem ser transformados em uma tabela filha separada no mapeamento lógico.
Coloque este conhecimento em prática agora mesmo executando o roteiro autoguiado:
👉 ATIVIDADE 02: MODELAGEM CONCEITUAL