Esta é uma aula curta e reveladora, porque demonstra na prática um princípio valioso: quando programamos contra uma boa abstração, decisões técnicas grandes tornam-se surpreendentemente fáceis de mudar. Na aula anterior, conectamos nosso programa ao PostgreSQL. Agora vamos apontar a mesma aplicação para um banco de dados diferente — o MySQL, outro dos bancos relacionais mais populares do mundo, muito comum em hospedagem de sites — e você verá que quase tudo permanece idêntico. A classe Produto não muda. O contexto quase não muda. As migrações funcionam igual. E, o mais importante, todo o LINQ das suas consultas permanece exatamente o mesmo. O que muda é o provedor e a string de conexão. Essa é a materialização concreta do valor do Entity Framework Core: ele abstrai o banco de dados, de modo que o banco torna-se um detalhe substituível.
Passo 1: instalar o MySQL
Como antes, precisamos do banco rodando. No WSL/Ubuntu, instalamos o servidor MySQL:
sudo apt-get update
sudo apt-get install -y mysql-server
# Inicia o serviço:
sudo service mysql start
# Entra no console do MySQL como administrador:
sudo mysql
Em Debian, esse comando falha com Unable to locate package mysql-server — e não é erro de digitação. O Debian não distribui o MySQL nos seus repositórios; ele empacota o MariaDB, que nasceu como um ramo do próprio MySQL e é compatível com ele para tudo o que faremos aqui. Nesse caso, troque os comandos acima por estes:
sudo apt-get install -y mariadb-server
sudo service mariadb start
sudo mariadb
O resto do capítulo segue igual, inclusive o provedor do EF Core — o Pomelo conversa com os dois. O que muda é o nome do serviço e o do cliente de linha de comando, e em boa parte das instalações o comando mysql continua existindo como atalho para o mariadb.
Dentro do console do MySQL, criamos o banco de dados e o usuário para o projeto, e saímos com EXIT;:
CREATE DATABASE loja_db;
CREATE USER 'curso'@'localhost' IDENTIFIED BY 'senha123';
GRANT ALL PRIVILEGES ON loja_db.* TO 'curso'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Esses comandos criam o banco loja_db, o usuário curso, e concedem a esse usuário permissão sobre o banco. (No Windows, o instalador oficial em mysql.com traz o servidor e uma interface gráfica; o restante é idêntico.) Com o MySQL de pé, vamos ao C# — e é aqui que você verá como pouca coisa muda.
Passo 2: trocar o provedor
No projeto, removemos o provedor do PostgreSQL e adicionamos o do MySQL. O provedor de MySQL mais usado chama-se Pomelo.EntityFrameworkCore.MySql:
dotnet remove package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Pomelo.EntityFrameworkCore.MySql
Lembra do conceito de provedor que enfatizei na aula anterior? Aqui está a razão da ênfase: é ele que adapta o EF Core à linguagem de cada banco. Trocar de banco começa por trocar o provedor — e, como você verá, quase termina aí também.
Passo 3: ajustar apenas a configuração da conexão
A única mudança relevante no código C# é o método que configura a conexão, dentro do contexto. Onde antes chamávamos UseNpgsql, agora chamamos UseMySql, com a string de conexão no formato do MySQL:
protected override void OnConfiguring(DbContextOptionsBuilder opcoes)
{
var conexao = "Server=localhost;Database=loja_db;User=curso;Password=senha123";
// A única linha que muda de banco para banco:
opcoes.UseMySql(conexao, ServerVersion.AutoDetect(conexao));
}
Compare com a aula anterior: trocamos UseNpgsql(...) por UseMySql(...). O ServerVersion.AutoDetect é uma pequena particularidade do provedor MySQL (ele precisa saber a versão do servidor para gerar os comandos corretos), mas o espírito é o mesmo: uma linha que diz "use este banco, conectando assim". Todo o resto do código permanece intocado.
Passo 4: o que NÃO muda (e por que isso importa)
Este é o ponto da aula. Veja o que continua exatamente igual ao do PostgreSQL:
// A CLASSE: idêntica. Uma classe C# não sabe qual banco a guarda.
class Produto
{
public int Id { get; set; }
public string Nome { get; set; } = "";
public decimal Preco { get; set; }
}
// A CONSULTA: idêntica. O mesmo LINQ, agora traduzido para o MySQL.
var baratos = await db.Produtos
.Where(p => p.Preco < 10)
.OrderBy(p => p.Nome)
.ToListAsync();
// SALVAR: idêntico.
db.Produtos.Add(new Produto { Nome = "Novo produto", Preco = 5m });
await db.SaveChangesAsync();
A classe, o DbSet, o LINQ das consultas, o SaveChangesAsync — tudo permanece igual. As migrações funcionam do mesmo modo (dotnet ef migrations add e database update); o EF Core apenas gera os comandos no dialeto do MySQL em vez do PostgreSQL. Você escreveu a aplicação uma vez, e ela roda sobre dois bancos de dados diferentes trocando essencialmente uma linha. Este é o retorno do investimento em abstração: a lógica do seu programa não conhece — nem precisa conhecer — qual banco está por baixo.
A lição maior: programe contra abstrações
Pare para apreciar o princípio que esta aula demonstra, pois ele vale muito além de bancos de dados. Quando você trabalha através de uma abstração — no caso, o EF Core, que oferece uma forma uniforme de falar com qualquer banco relacional —, você fica isolado dos detalhes concretos por baixo dela. Isso significa que esses detalhes podem mudar sem afetar o seu código. Trocar PostgreSQL por MySQL afetou apenas o ponto onde o banco é configurado; toda a lógica que usa os dados permaneceu intocada, porque ela conversava com a abstração, não com o banco específico. Esse é um princípio de projeto poderoso: programe contra abstrações, não contra detalhes concretos, e você ganha a liberdade de trocar os detalhes depois. Você o encontrará repetidamente conforme avançar, e reconhecerá seu valor toda vez que uma mudança que parecia enorme se revelar pequena, graças a uma boa abstração no lugar certo.
Uma nota de honestidade
Para ser justo com a realidade: a troca é quase totalmente transparente, mas não perfeitamente, em casos avançados. Recursos muito específicos de um banco (certos tipos de dados especiais, funções nativas particulares) podem não ter equivalente exato no outro, e aí surgem pequenos ajustes. Mas para a esmagadora maioria das aplicações — as que usam tipos comuns e consultas LINQ padrão, como a nossa — a troca é tão simples quanto vimos. Não prometo mágica perfeita; prometo que a abstração cobre o caso comum com folga, e é isso que a torna valiosa. Saber que existem exceções em casos avançados apenas o torna um programador mais consciente; não diminui o enorme valor prático de uma abstração que resolve a vasta maioria dos casos com uma troca de linha.
A mesma aplicação passou a rodar sobre outro banco com uma alteração notavelmente pequena: trocar o pacote do provedor e ajustar a linha de conexão. As classes, o contexto, as consultas e toda a lógica permaneceram exatamente como estavam.
O que NÃO mudou é a lição, e ela vale muito além de bancos de dados: programar contra uma abstração, e não contra uma implementação específica, é o que permite trocar uma peça da infraestrutura sem reescrever o sistema. A nota de honestidade também fica registrada — a portabilidade é ampla, mas não absoluta, e recursos muito particulares de um banco podem exigir ajuste.
Fontes e leituras recomendadas
- Provedores de banco de dados do EF Core — a lista oficial de provedores e a natureza plugável que permite trocar de banco; a base desta aula.
- Provedor Pomelo para MySQL — o provedor de MySQL usado aqui, com detalhes de configuração.
- Strings de conexão do EF Core — como as strings de conexão variam entre provedores.
- Instalação do MySQL — os instaladores oficiais; para o WSL, o pacote
mysql-serverdo Ubuntu. - Princípio de inversão de dependência — "programe contra abstrações", o fundamento que esta aula demonstra.
Exercícios
Exercício 1
Instale o MySQL (no WSL ou no Windows), crie o banco loja_db e o usuário curso com privilégios, e confirme o acesso pelo console do MySQL. Anote a string de conexão.
Ver resposta
✓ Resposta: Após instalar e iniciar o serviço, sudo mysql abre o console; os comandos de criação (CREATE DATABASE, CREATE USER, GRANT, FLUSH PRIVILEGES) preparam o banco e o usuário. A string de conexão é Server=localhost;Database=loja_db;User=curso;Password=senha123. Conseguir conectar com essas credenciais confirma que o servidor está no ar e o usuário tem acesso.
Exercício 2
Pegue o projeto da aula anterior (PostgreSQL), remova o provedor Npgsql, adicione o Pomelo, e altere apenas o OnConfiguring para usar UseMySql. Gere e aplique as migrações, e confirme que a aplicação funciona igual, agora sobre o MySQL.
Ver resposta
✓ Resposta: Após dotnet remove package Npgsql.EntityFrameworkCore.PostgreSQL e dotnet add package Pomelo.EntityFrameworkCore.MySql, altera-se o OnConfiguring para opcoes.UseMySql(conexao, ServerVersion.AutoDetect(conexao)). Gerando as migrações e aplicando com database update, o EF Core cria a tabela no MySQL, e a aplicação — classe, LINQ, SaveChangesAsync — roda igual, agora sobre o novo banco. O comportamento é idêntico ao da versão PostgreSQL.
Exercício 3
Liste, comparando as duas últimas aulas, exatamente o que precisou mudar para trocar de PostgreSQL para MySQL, e o que permaneceu idêntico. Em termos de código C#, quantas linhas de fato mudaram?
Ver resposta
✓ Resposta: Mudaram: o pacote do provedor (de Npgsql para Pomelo), o método de configuração no OnConfiguring (de UseNpgsql para UseMySql, com o ServerVersion.AutoDetect), e a string de conexão no formato do MySQL. Permaneceram idênticos: a classe Produto, o DbSet, todas as consultas LINQ, o SaveChangesAsync e o fluxo de migrações. Em termos de código C#, essencialmente uma linha de fato mudou (a do Use...), além da troca de pacote (feita por comando, não no código) e da string de conexão.
Exercício 4
Explique, com suas palavras, o princípio "programe contra abstrações, não contra detalhes concretos", usando a troca de banco desta aula como exemplo. Como o EF Core (a abstração) isolou o seu código do banco específico?
Ver resposta
✓ Resposta: O princípio "programe contra abstrações, não contra detalhes concretos" significa escrever seu código de modo que ele dependa de uma interface uniforme (a abstração) em vez dos detalhes específicos de uma implementação concreta — assim, esses detalhes podem mudar sem afetar seu código. Na troca de banco desta aula, o EF Core é a abstração: ele oferece uma forma uniforme de falar com qualquer banco relacional (classes, DbSet, LINQ, SaveChangesAsync), e o seu código conversa com essa forma uniforme, não com o PostgreSQL ou o MySQL diretamente. Por isso, trocar o banco concreto por baixo (o "detalhe") afetou apenas o ponto onde o banco é configurado; toda a lógica que usa os dados, por depender da abstração e não do banco específico, permaneceu intocada. O EF Core isolou o seu código do banco: o seu programa nunca "soube" qual banco havia por baixo, então mudar esse banco não o afetou.
Exercício 5
Sem código: a aula afirma que a troca de banco é "quase, mas não perfeitamente" transparente. Descreva um cenário em que a troca poderia exigir ajustes além da configuração da conexão, e explique por que a abstração ainda vale muito a pena mesmo assim.
Ver resposta
✓ Resposta: Um cenário: se a aplicação usasse um tipo de dado especial ou uma função nativa exclusiva de um banco (por exemplo, um tipo geográfico do PostgreSQL, ou uma função de texto específica sem equivalente no MySQL), a troca exigiria adaptar essa parte, pois o outro banco não a suportaria da mesma forma. Ainda assim, a abstração vale muito a pena porque cobre com folga o caso comum — tipos e consultas padrão, que são a maioria —, reduzindo a troca a essencialmente uma linha na esmagadora parte do código; os poucos pontos específicos de um banco ficam isolados e identificáveis, em vez de espalhados por toda a aplicação. Trocar "quase tudo automaticamente e ajustar o pouco que resta" é incomparavelmente melhor do que reescrever todo o acesso a dados à mão a cada mudança de banco. A existência de exceções em casos avançados não diminui o valor prático imenso de uma abstração que resolve a maioria dos casos com uma troca mínima.