Tabelas, colunas, tipos de dados e relações entre entidades com Room (Android) e Core Data (iOS) — do modelo conceitual à implementação no dispositivo.
Por que o banco de dados do aluno fica uma bagunça na segunda entidade?
Na primeira aula prática, o estudante cria uma tabela simples — tarefas com título e status — e o CRUD funciona. Na terceira aula, o desafio cresce: o app precisa de categorias. A reação mais comum é adicionar uma coluna categoria do tipo String diretamente na tabela de tarefas, repetindo o nome da categoria em cada registro.
O app funciona. Mas quando o professor pede para renomear a categoria “trabalho” para “profissional”, o estudante percebe que precisaria atualizar dezenas de registros individualmente. O custo do atalho se revela: sem um modelo de dados estruturado com relações entre entidades, qualquer mudança vira uma operação em massa propensa a inconsistências.
Este artigo documenta o caminho correto: modelar duas entidades (Tarefa e Categoria), estabelecer o relacionamento via chave estrangeira, e implementar a estrutura no Room ou no Core Data.
Custo concreto de não estruturar relações: dados duplicados em cada linha da tabela, impossibilidade de renomear categorias em cascata, consultas lentas por ausência de filtros relacionais e impossibilidade de escalar para subcategorias ou filtros compostos sem reescrever todo o banco.
O contexto da aula: estrutura antes da prática
Esta é a terceira aula da Unidade 2. As duas anteriores estabeleceram os tipos de armazenamento e o CRUD básico com uma entidade. Agora o foco se desloca para a arquitetura do banco: como múltiplas tabelas se organizam, como se relacionam e qual o impacto dessa decisão na performance e manutenibilidade do app.
Formato: 45 minutos, em grupo, computador com internet. Entrega de texto-síntese no AVA respondendo às três perguntas do roteiro. Antes de qualquer linha de código, o roteiro orienta o grupo a desenhar o modelo no papel — passo deliberado para forçar o raciocínio estrutural antes da implementação.
Conjunto de entidades (tabelas), atributos (colunas com tipos definidos) e relacionamentos (vínculos via chaves estrangeiras) que organizam os dados de uma aplicação de forma eficiente, escalável e livre de redundâncias, implementados localmente via Room ou Core Data.
Quais são os três componentes da estrutura de um banco de dados?
| Componente | Conceito | Exemplo no app de tarefas | Papel no Room |
|---|---|---|---|
| Entidade (Tabela) | Representa um objeto ou conjunto de dados homogêneo | Tarefa, Categoria | @Entity(tableName = "tarefas") |
| Atributo (Coluna) | Característica específica de uma entidade, com tipo definido | titulo: String, status: String, id: Int | Propriedade da data class |
| Relacionamento | Vínculo lógico entre entidades via chave estrangeira | categoriaId em Tarefa → id em Categoria | @ForeignKey ou campo referencial |
O diagrama do modelo: Tarefa ↔ Categoria
O app de controle de tarefas requer que cada tarefa esteja associada a uma categoria. A solução correta é criar duas entidades com um relacionamento N:1 — muitas tarefas para uma categoria — mediado pelo campo categoriaId na tabela tarefas.
O campo categoriaId na tabela tarefas armazena o id da categoria associada. Relacionamento N:1 — várias tarefas por categoria.
Por que isso evita duplicação?
Sem a entidade separada, o campo categoria em cada tarefa seria um texto como “Trabalho”. Se houver 50 tarefas com essa categoria e o nome mudar, seriam 50 atualizações. Com a entidade Categoria e a chave estrangeira, basta atualizar um único registro na tabela categorias — a mudança se propaga automaticamente a todas as tarefas associadas.
Como implementar a estrutura com Room (Android)?
- Configurar ambiente: dependências do Room no
build.gradle+ pluginkotlin-kapt. Sincronizar antes de criar qualquer classe. - Definir as duas entidades:
Tarefacom campos id, titulo, descricao, status e categoriaId;Categoriacom id e nome. Ambas anotadas com@Entity. - Criar os DAOs:
TarefaDaocom inserção, busca por categoria e remoção;CategoriaDaocom inserção e listagem. A query de filtro por categoria usa o parâmetro:categoriaId. - Implementar o AppDatabase: declarar ambas as entidades no array
entitiesda anotação@Databasee expor os dois DAOs como métodos abstratos. - Testar o relacionamento: inserir categorias primeiro, depois tarefas com
categoriaIdválido. Verificar a query de filtro por categoria.
Implementação completa: duas entidades relacionadas no Room
Template 1 — Entidades Tarefa e Categoria
// ── ENTIDADE: Tarefa ──
@Entity(tableName = "tarefas")
data class Tarefa(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val titulo: String,
val descricao: String,
val status: String, // "pendente" | "completa"
val categoriaId: Int // FK → Categoria.id
)// ── ENTIDADE: Categoria ──
@Entity(tableName = "categorias")
data class Categoria(
@PrimaryKey(autoGenerate = true) val id: Int = 0,
val nome: String // "trabalho", "pessoal", etc.
)Template 2 — TarefaDao e CategoriaDao com query relacional
@Dao
interface TarefaDao {
@Insert
fun inserirTarefa(tarefa: Tarefa)// READ com filtro relacional — retorna tarefas de uma categoria
@Query("SELECT * FROM tarefas WHERE categoriaId = :categoriaId")
fun obterTarefasPorCategoria(categoriaId: Int): List<Tarefa>@Delete
fun removerTarefa(tarefa: Tarefa)
}@Dao
interface CategoriaDao {
@Insert
fun inserirCategoria(categoria: Categoria)@Query("SELECT * FROM categorias")
fun obterTodasCategorias(): List<Categoria>
}Template 3 — AppDatabase com múltiplas entidades
// Declarar as duas entidades no array entities
@Database(entities = [Tarefa::class, Categoria::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
abstract fun tarefaDao(): TarefaDao
abstract fun categoriaDao(): CategoriaDao
}// Uso: inserir categoria antes das tarefas (FK exige id válido)
Thread {
val db = Room.databaseBuilder(ctx, AppDatabase::class.java, "app-db").build()// 1. Criar categoria
db.categoriaDao().inserirCategoria(Categoria(nome = "Trabalho"))// 2. Buscar id gerado
val catId = db.categoriaDao().obterTodasCategorias().first().id// 3. Criar tarefa com FK válida
db.tarefaDao().inserirTarefa(
Tarefa(titulo = "Revisar relatório", descricao = "Q3 2025",
status = "pendente", categoriaId = catId)
)// 4. Buscar tarefas da categoria
val tarefas = db.tarefaDao().obterTarefasPorCategoria(catId)
}.start()Template 4 — Core Data (iOS): duas entidades com relacionamento
// No Data Model Editor: criar entidade Tarefa e Categoria
// Adicionar relacionamento "categoria" em Tarefa → aponta para Categoriaimport CoreDataclass TarefaRepository {
private let context: NSManagedObjectContext// Inserir categoria
func inserirCategoria(nome: String) -> Categoria {
let cat = Categoria(context: context)
cat.nome = nome
try? context.save()
return cat
}// Inserir tarefa com relacionamento
func inserirTarefa(titulo: String, descricao: String,
status: String, categoria: Categoria) {
let tarefa = Tarefa(context: context)
tarefa.titulo = titulo
tarefa.descricao = descricao
tarefa.status = status
tarefa.categoria = categoria // relacionamento direto
try? context.save()
}// Buscar tarefas por categoria
func tarefasPorCategoria(categoria: Categoria) -> [Tarefa] {
let req: NSFetchRequest<Tarefa> = Tarefa.fetchRequest()
req.predicate = NSPredicate(format: "categoria == %@", categoria)
return (try? context.fetch(req)) ?? []
}
}Caso aplicado: app de controle de tarefas com categorias no laboratório
Contexto da atividade: o grupo foi “contratado” para desenvolver um app de controle de tarefas pessoais com categorias (trabalho, pessoal, etc.). Cada tarefa tem título, descrição e status; cada tarefa pertence a uma categoria específica. O grupo precisa definir as entidades, os tipos de dados de cada coluna e o relacionamento entre elas antes de implementar.
Decisão crítica que o grupo enfrentará: inserir a categoria primeiro ou a tarefa primeiro? O campo categoriaId precisa de um id válido da tabela categorias — se a categoria ainda não existir, a inserção falhará ou gerará um registro órfão. Isso força o grupo a entender a ordem de dependência entre entidades relacionadas.
Perguntas do roteiro para o texto-síntese: importância das relações entre entidades; como entidades separadas melhoram a organização; impacto da estrutura na performance. As respostas devem ser entregues no AVA ao término da aula.
Síntese: a estrutura de um banco de dados móvel depende da correta definição de entidades (tabelas), atributos (colunas com tipos) e relacionamentos (chaves estrangeiras entre tabelas). O Room implementa essa estrutura via @Entity, @Dao e @Database. Separar entidades evita duplicação, facilita manutenção e permite consultas relacionais eficientes — princípio de normalização aplicado ao desenvolvimento mobile.
Perguntas frequentes sobre estrutura e relacionamentos de banco de dados mobile
O que é a estrutura de um banco de dados em aplicações móveis?
A estrutura de um banco de dados móvel compreende entidades (tabelas que representam objetos), atributos (colunas com características e tipos) e relacionamentos (vínculos entre tabelas via chaves estrangeiras). Room e Core Data traduzem essa estrutura em código Kotlin ou Swift executado diretamente no dispositivo.
Qual a importância de definir relações entre entidades em um banco de dados móvel?
Relações organizam os dados logicamente, evitam redundâncias e permitem operações complexas como buscar todas as tarefas de uma categoria específica. Sem relações, dados precisam ser duplicados em cada registro, aumentando o volume e a probabilidade de inconsistências. Com relações, uma mudança na categoria se propaga automaticamente a todas as tarefas associadas.
Como entidades separadas melhoram a organização do banco de dados?
A separação aplica o princípio da normalização: evita duplicação e facilita o gerenciamento. Com Categoria como entidade separada, renomear “trabalho” para “profissional” exige atualizar apenas um registro. Também facilita escalabilidade — adicionar subcategorias ou filtros compostos não exige reestruturação do banco.
O que é chave estrangeira (foreign key) em banco de dados mobile?
Chave estrangeira é um campo que referencia a chave primária de outra tabela, estabelecendo o relacionamento entre elas. No Room, o campo categoriaId na entidade Tarefa é uma foreign key que aponta para o id da tabela Categoria, permitindo consultas como “buscar todas as tarefas da categoria Trabalho”.
Como a estrutura do banco de dados impacta a performance de um app móvel?
Relações claramente definidas tornam consultas filtradas mais rápidas. Sem estrutura, o app processa dados duplicados e realiza mais operações de verificação, aumentando consumo de CPU, memória e bateria. Uma estrutura bem planejada reduz o uso de recursos do dispositivo, essencial para uma boa experiência do usuário em hardware limitado.
>_ Unidade 2 completa — Armazenamento de Dados e Repositórios
Todas as aulas, roteiros de atividade e templates de código disponíveis no blog do Professor Comia.
acessar professorcomia.com.br →Conclusão: modelar antes de codificar
A principal virada pedagógica desta aula não é técnica — é procedimental. O roteiro instrui o grupo a desenhar o modelo no papel antes de abrir o IDE. Esse passo aparentemente simples impõe o raciocínio estrutural antes da implementação: quais entidades existem, quais são seus campos, como elas se relacionam.
O desenvolvedor que modela antes de codificar comete menos erros de estrutura, refatora menos e escala mais facilmente. Esse hábito — pensar em tabelas, colunas e relações antes de pensar em queries — é a competência central desta aula e uma das mais duráveis do curso técnico de Desenvolvimento de Sistemas.
📘 Gostou do que viu aqui no laboratório? No Professor com IA eu mostro, passo a passo, como você também pode criar ferramentas assim — mesmo sem saber programar.