Entity Framework core uno a relación de muchos

c# entity-framework-core one-to-many

Pregunta

Estoy tratando de construir un código de primer modelo de datos con una relación de uno a muchos.

Hay un UserDTO y un modelo de RoleDTO con el Usuario que contiene uno o varios roles.

Algunos códigos simplificados para el RoleDTO es:

internal class RoleDTO
{
    public UserDTO User { get; set; }

    public string Value { get; set; }

    public RoleDTO()
    {

    }
}

Y el UserDTO simplificado:

internal class UserDTO
{
    public string Email { get; set; }

    public string FullName { get; set; }

    public string UserName { get; set; }

    public virtual ICollection<RoleDTO> Roles { get; set; }

    public UserDTO()
    {

    }
}

Y finalmente la clase que hereda de DBContext.

class StorageContext : DbContext
{
    public DbSet<UserDTO> Users { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        optionsBuilder.UseSqlServer(@"My_Connection_String");
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<UserDTO>().HasKey(entity => entity.Email);
        modelBuilder.Entity<UserDTO>().HasMany(entity => entity.Roles);

        modelBuilder.Entity<RoleDTO>().HasOne<UserDTO>().WithMany(x => x.Roles);
        modelBuilder.Entity<RoleDTO>().HasKey(x => x.Value);
    }
}

Cuando ejecuto mi migración de agregar y no tengo ninguna base de datos o carpeta de migraciones (e incluso si la ejecuté después de tener algunas columnas de todos modos) la tabla de roles se crea con columnas adicionales que hacen referencia a la dirección de correo electrónico del usuario.

Solo quiero 2 columnas en mi tabla de roles, una que es la dirección de correo electrónico del usuario y es un FK para la PK de correo electrónico del Usuario, y la otra que es un valor de cadena que combinado con la clave externa crea una clave principal compuesta en la tabla de usuarios . Diagrama de abajo:

*******************************
* Role                        *
*******************************
* User_Email - string/varchar *
* Value - string /varchar     *
*******************************
FK - User_Email to User table Email column
PK - User_Email, Value compound primary key

¿Alguien sabe cómo lograr esto usando la API fluida o las anotaciones de datos?

¡Gracias!

Respuesta aceptada

En primer lugar, la clase UserDTO no tiene una propiedad llamada User_Email . Puede definir una propiedad de sombra en el modelo utilizando EF, pero considerando que desea que esté en el modelo, debe definir la propiedad en la clase public string User_Email

Una vez que haya definido la propiedad anterior en la clase o una propiedad de la sombra definida en el modelo utilizando la API fluida,

Para definir una clave primaria compuesta, debe usar la API fluida de HasKey . No puede utilizar anotaciones de datos para definir la clave primaria compuesta.

Para definir User_Email, Value como compuesto PK, escriba el siguiente código en OnModelCreating (después de definir la propiedad de la sombra si va por ese camino)

modelBuilder.Entity<UserDTO>().HasKey(e => new { e.User_Email, e.Value });

Para especificar la propiedad de la clave externa para la relación, puede usar ForeignKeyAttribute en fk property / navigation o puede usar la API fluida HasForeignKey .

Para configurar User_Email como FK en la tabla UserDTO , suponiendo que UserDTO User en RoleDTO & ICollection<RoleDTO> Roles en UserDTO son navegaciones para esta relación.

Con las anotaciones de datos, escriba ForeignKey("User") en la propiedad User_Email o escriba ForeignKey("User_Email") en cualquier navegación ( User / Roles ). Recuerde que no puede usar esto si tiene User_Email como propiedad de la sombra.

Con Fluent API, escriba el siguiente código en OnModelCreating para configurar la relación completamente

modelBuilder.Entity<RoleDTO>().HasOne(e => e.User).WithMany(e => e.Roles).HasForeignKey(e => e.User_Email);

Anteriormente creará una relación de uno a varios mediante el User navegaciones de User y Roles que utiliza User_Email como propiedad de clave externa.

La razón por la que su código no funcionó correctamente es

  1. Usando HasKey , ha definido una propiedad única PK en lugar de PK compuesta.
  2. No ha utilizado el método HasForeignKey para especificar la propiedad de clave externa, por lo que EF agregará una propiedad de sombra para usted. Además, en la configuración de su relación, solo utilizó la navegación de Roles . EF intentará crear otra relación utilizando User navegación del User , haciendo efectivamente 2 relaciones entre UserDTO y RoleDTO . Esa es la razón por la que obtuvo columnas adicionales porque EF creó las propiedades de sombra para ser utilizadas como propiedades de clave externa por convención.

Respuesta popular

No estoy seguro de lo que intenta lograr con esto, pero trabajar con claves compuestas en ORM puede ser complejo y un área que puede ser impredecible. Por lo tanto, aconsejaría ir en contra de las claves compuestas a menos que tenga una buena razón real.

Yo sugeriría no usar la dirección de correo electrónico como un PK en ningún lugar. Use un Int32 / Int64 generado único o incluso Guid como clave principal (esto se reflejará en su tabla de roles como una clave externa una vez que haya configurado la relación) y coloque un índice en su columna de correo electrónico (en su tabla de usuario) que tenga una restricción única en él. Puede agregar el índice en su script de migración. Al menos de esta manera, puede mantener la identidad si la dirección de correo electrónico cambiara (si eso es lo que quiere).

Espero que esto ayude.



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué