EntityFramework Core - SnakeCase
Veja como fazer convenções de nomenclatura SnakeCase para o EntityFramework Core!
Nosso objetivo aqui é mostrar uma solução para o EntityFramework Core + PostgreSQL.
Basicamente existem 4 tipos de nomenclaturas que usamos para escrever nossos códigos: PascalCase, CamelCase, SnakeCase e SpinalCase, já que iremos abordar um assunto que se trata de um dos casos citados, nada mais justo do que resumir cada um deles.
ResumidÃO!
PascalCase
Exemplo:
BlogRafael = "www.ralms.io";
CamelCase
Exemplo:
blogRafael = "www.ralms.io";
SnakeCase
Exemplo:
blog_rafael = "www.ralms.io";
Blog_Rafael = "www.ralms.io";
SpinalCase
Exemplo:
blog-rafael = "www.ralms.io";
Blog-Rafael = "www.ralms.io";
Vamos codar?!
O que me levou a escrever esse artigo?
Mas eu queria usar todo recurso que o EntityFramwork Core me proporciona, o EFCore por Design cria os nomes de tabelas e campos por reflection, isso significa que se tiver uma propriedade PascalCase, da mesma forma será atribuido o nome a este, existe a possibilidade de usarmos propriedades de sombras(ou Fluent API), mas esse é o trabalho que eu não gostaria de fazer e nem me procupar.
Cada um tem sua forma de aplicar nomeclaturas em seus projetos, quando se trata banco de dados eu gosto de utilizar SnakeCase, acredito que é muito mais legÃvel a leitura e suporte.
E foi por isso que escrevi essa pequena extensão para nosso ModelBuilder, tudo isso por que aqueles que vem do SQL Server sabe que ele não se importa com maiúsculas e minúsculas para nomes de colunas e tabelas, cenário muito diferente para PostgreSQL que faz distinção entre maiúsculas e minúsculas, mas aqui está a solução para isso, e então com alguns pequenos ajustes e uma simples função Regex, serei mais feliz 😄, VIVA REGEX!
public static class LinqSnakeCase
{
public static void ToSnakeNames(this ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
entity.Relational().TableName = entity.Relational().TableName.ToSnakeCase();
foreach (var property in entity.GetProperties())
{
property.Relational().ColumnName = property
.Relational()
.ColumnName
.ToSnakeCase();
}
foreach (var key in entity.GetKeys())
{
key.Relational().Name = key.Relational().Name.ToSnakeCase();
}
foreach (var key in entity.GetForeignKeys())
{
key.Relational().Name = key.Relational().Name.ToSnakeCase();
}
foreach (var index in entity.GetIndexes())
{
index.Relational().Name = index.Relational().Name.ToSnakeCase();
}
}
}
private static string ToSnakeCase(this string name)
{
return string.IsNullOrWhiteSpace(name)
? name
: Regex.Replace(
name,
@"([a-z0-9])([A-Z])",
"$1_$2",
RegexOptions.Compiled,
TimeSpan.FromSeconds(1)).ToLower();
}
}
Veja como ficou nosso SampleContext
using Microsoft.EntityFrameworkCore;
using System;
namespace SnakeCase
{
class Program
{
static void Main(string[] args)
{
using (var db = new SampleContext())
{
// Nossa saÃda SQL
var script = db.Database.GenerateCreateScript();
}
}
}
public sealed class SampleContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseNpgsql(
"Host=127.0.0.1;Username=postgres;Password=XXX;Database=TestSnake",
_ => _.EnableRetryOnFailure());
}
}
protected override void OnModelCreating(ModelBuilder modelo)
{
modelo.Entity<TestSnakeCase>();
// Aqui está nossa mágica!
modelo.ToSnakeNames();
}
}
public class TestSnakeCase
{
public int Id { get; set; }
public int CodigoIBGE { get; set; }
public string NomeCompleto { get; set; }
public int AnoNascimento { get; set; }
public DateTime DataCadastro { get; set; }
}
}
Nossa saÃda SQL
CREATE TABLE test_snake_case (
id serial NOT NULL,
codigo_ibge integer NOT NULL,
nome_completo text NULL,
ano_nascimento integer NOT NULL,
data_cadastro timestamp without time zone NOT NULL,
CONSTRAINT pk_test_snake_case PRIMARY KEY (id)
);
#mvpbuzz #mvpbr #mvp #developerssergipe #share #vscode #postgresql #efcore
Deixe um comentário