Vamos a intentar explicar un escenario de desarrollo en Visual Studio, en un modelo de diseño que parte de base de datos existente, SQL Server en este caso (Database first), en el cual integramos la autenticación mediante ASP.NET Core Identity con las tablas ya existentes relacionadas con lo usuarios de Identity; todo ello utilizando un único DbContext…
Utilizaremos la extensión EF Core Power Tools para facilitar convertir nuestras tablas en objetos y clases de nuestra aplicación, en el ejemplo se realiza con Blazor pero serviría para otro proyecto de .NET diferente.
Cuando generamos nuestro DbContext desde la extensión debemos hacerlo heredar de la clase IdentityDbContext:
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace MainMindSpace
{
public class MiContexto : IdentityDbContext<ApplicationUser>
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder); // Llamada al método base
}
public class ApplicationUser : IdentityUser
{
// Puedes agregar propiedades adicionales aquí si es necesario
}
}
Ahora bien, si en el proceso de «Reverse engineer» hemos seleccionado las tablas que genera nuestro modelo Identity, empecerán a aparecer errores en tiempo de ejecución al acceder a nuestro modelo de base de datos:
Cannot use table 'AspNetUsers' for entity type 'AspNetUsers' since it is being used for entity type 'ApplicationUser' and potentially other entity types, but there is no linking relationship. Add a foreign key to 'AspNetUsers' on the primary key properties and pointing to the primary key on another entity type mapped to 'AspNetUsers'.
La clase de la que heredamos, ya tiene mapeadas estas tablas, por lo que no debemos añadirlas desde EF Core Power Tools:
Si tenemos tablas propias que se relacionan con las de la clase heredada, deberemos añadir a mano la relación existente entre ambas, utilizando API fluent de Entity Framework. Por ejemplo, una tabla «presupuestos» con el campo «responsable» como clave externa apuntando ApplicationUser.Id (lo que sería la tabla AspNetUser.Id)
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<presupuestos()
.HasOne(p => p.responsableNavigation)
.WithMany()
.HasForeignKey(p => p.responsable) // La clave externa en presupuestos
.HasPrincipalKey(u => u.Id) // La clave principal en ApplicationUser
.IsRequired(true); // Si es opcional o no
// Otras configuraciones de modelo...
}
Se mantiene la nomenclatura añadiendo «Navigation» al campo con la clave externa:
public partial class presupuestos
{
public long id_presupuesto { get; set; }
public string? descripcion { get; set; }
public string responsable { get; set; } = null!;
public virtual ApplicationUser responsableNavigation { get; set; } = null!;
...
}
NOTA: en las últimas versiones de Identity, el Id ha pasado a ser cadena de texto de 450 caracteres, en lugar de Guid o similar. Si realizas migración desde Membership, revisa la documentación.
Definiendo dentro del método «OnModelCreating» logramos que Entity Framework pueda entender correctamente la estructura de la base de datos y pode realizar consultas con datos relacionados.