Ir al contenido principal

Renombrar las tablas de ASP .NET Identity para Postgresql

Los modelos definidos en ASP .NET Identity están diseñados para motores de bases de datos que usen los nombres de las tablas y columnas en mayúsculas. Sin embargo, en otros, como por ejemplo Postgresql, los nombres de tablas y columnas se escriben en minúsculas. Cuando ejecutamos una migración, todas las tablas y columnas se crearán con los nombres en mayúsculas. En el caso particular de Postgresql esto puede resultar incómodo cuando queremos escribir consultas SQL a mano, ya que, esto nos obligará a escribir cada nombre de tabla y columna entre comillas. 

Para remediar este problema debemos por un lado renombrar todas las tablas de Identity y por otro implementar un mecanismo para que los nombres de las propiedades en las entidades de Identity sean tranformadas automáticamente. A continuación vamos a tratar ambos requisitos.

Transformación automática de las propiedades

En las clases de Identity, los nombres de las propiedades siguen la convención pascal. Sin embargo en Postgresql siguen la convención snake. Una solución para adaptar los nombres sería reescribir todas las propiedades de las clases de Identity, lo cual no es para nada recomendable. Sin embargo, podemos transformar los nombres en tiempo real usando una librería, que tranformará el nombre de una propiedad en función de la operación que se esté realizando. Cuando se generen las consultas SQL, la librería transformará los nombres al formato snake, para que sean ejecutadas en la base de datos. Cuando se recuperen datos desde la base de datos, la librería transformará los nombres al formato pascal para que coincidan con los nombres de las propiedades en las clases de Identity. De este modo la librería actúa como un proxy entre EntityFramework y PostgreSQL para permitir que se sigan las convenciones en cada extremo.

Existen diversas alternativas que permiten realizar esta tarea, pero nosotros nos decantamos por EFCore.NamingConventions, que soporta diferentes tipos de conversiones: snake en minúscula y mayúscula, todo en minúsculas, todo en mayúsculas y camel.

Ten en cuenta que si usas esta librería con una base de datos existente se creará una nueva migración que renombrará todas las tablas, columnas, índices, claves foráneas, etc., cuyos resultados pueden ser imprevisibles. Úsala con cuidado en estos casos.

Instala el paquete nuget EFCore.NamingConventions en el proyecto. Modifica el archivo Program.cs para configurar el uso de la librería:

//...

builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseNpgsql(connectionString).UseSnakeCaseNamingConvention());

//...

Lo que estamos haciendo en el código anterior, es, definir un conversor de formato snake para el contexto de datos ApplicationDbContext que usa la librería Npgsql como adaptador de datos. De este modo queda configurado el proxy.

Renombrar las tablas ASP .NET Identity

El modelo de datos de Identity está definido usando instrucciones de construcción de modelos, por lo cual, aun cuando usamos la librería, los nombres de las tablas no se transforman automáticamente. De hecho, los nombres de las tablas creadas no coinciden con los nombres de las entidades. Por lo cual, debemos sobreescribir los nombres de la tabla usando el mismo método:

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using pocogen.Entities;

namespace myProject.Data
{
    public class ApplicationDbContext : IdentityDbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }

        //...

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);

            builder.Entity<IdentityUser>().ToTable("identity_users");
            builder.Entity<IdentityRole>().ToTable("identity_roles");
            builder.Entity<IdentityUserToken<string>>().ToTable("identity_user_tokens");
            builder.Entity<IdentityUserRole<string>>().ToTable("identity_user_roles");
            builder.Entity<IdentityRoleClaim<string>>().ToTable("identity_role_claims");
            builder.Entity<IdentityUserClaim<string>>().ToTable("identity_user_claims");
            builder.Entity<IdentityUserLogin<string>>().ToTable("identity_user_logins");
        }

        //...
    }
}

En el código anterior, reescribimos el método OnModelCreating que es llamado cada vez que se crea el modelo de datos. Dentro de este método podemos definir todas las características de las entidades. Para renombrar las tablas, hemos definido el nombre de la tabla correspondiente a cada entidad de Identity. En el ejemplo hemos usado el prefijo identity_ para las tablas, pero, tú puedes nombrarlas como tu quieras, según tus necesidades y convenciones.

Después de crear una migración y de aplicarla a la base de datos, todas las tablas se habrán creado con el nombre definido y todas las columnas estarán en formato snake.