Entity Framework 6 Fluent Api Configuración de una relación a una

[Table("Child", Schema = "dbo")]
public partial class Child
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public int Id { get; set; }

    public int? Parent1Id { get; set; }

    public int? Parent2Id { get; set; }

    public virtual Parent Parent1 {get; set}   
    public virtual Parent Parent2 {get; set}      
}

[Table("Parent", Schema = "dbo")]
public partial class Parent
{
    [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
    [Key]
    public int Id { get; set; }

    public virtual Child Child1 { get; set; }
    public virtual Child Child2 { get; set; }
  //modelBuilder below would work if I had this
  //public virtual ICollection Child1 { get; set; }

}

Esto significa ser una relación entre pariente y niño. Parent1Id y Parent2 Es nulo.

Sólo encontré ejemplos (con FluentAPI) para una relación de uno a muchos y si tuviera una colección de Child in Parent tendría que hacer algo como:

modelBuilder.Entity()
                .HasMany(e => e.Child1)
                .WithOptional(e => e.Parent1)
                .HasForeignKey(e => e.Parent1Id);
modelBuilder.Entity()
                .HasMany(e => e.Child2)
                .WithOptional(e => e.Parent2)
                .HasForeignKey(e => e.Parent2Id);

El niño tendrá un pariente de referencia FK. El pariente no tiene hijos de referencia FK.

Mi pregunta es, ¿cómo puedo hacer esto como una relación uno a uno usando EF 6.x? Vi el método HasOne() pero eso es de EFCore así que estoy fuera de opciones en este.

Gracias.

Pregunta hecha hace 3 años, 4 meses, 28 días - Por codechampion


5 Respuestas:

  • Nota: Las relaciones individuales no son técnicamente posibles en MS SQL Server. Estas siempre serán relaciones de uno a cero o uno. EF forma relaciones de uno a uno en entidades no en el DB.

    https://www.entityframeworktutorial.net/code-first/configure-one-to-relationship-in-code-first.aspx

    Respondida el Dec 18, 2020 a las 19:33 - por debugdynamo05ee

    Votos positivos: 0 | Votos negativos: 0

  • EF6 admite naturalmente sólo relaciones individuales usando el llamado asociaciones principales comunes, donde el PK dependiente también se utiliza como FK. Sin embargo no son aplicables en este escenario (cuando usted necesita más de una relación entre dos entidades). Así que necesitas relaciones basadas en un solo FK.

    Son compatibles, pero con las siguientes restricciones:

    • EF6 no creará la limitación/índice única en la columna FK necesaria para ejecutar "a 1" (o "a 0 o 1") en la base de datos, por lo que desde el punto de vista de la base de datos serán uno a otro.
    • No se admiten propiedades explícitas FK (nota la falta de HasForeignKey API fluida al configurar una relación entre uno y uno). Tienes que eliminarlos y trabajar sólo con propiedades de navegación. El FK columna nombre se puede especificar utilizando MapKey dentro Map método.

    Usted tiene que aceptar estas restricciones, de lo contrario no puede utilizar EF6 con tal modelo.

    Comience eliminando las propiedades explícitas de FK del modelo:

    // remove these:
    //public int? Parent1Id { get; set; }
    //
    //public int? Parent2Id { get; set; }
    

    Lo siguiente a considerar es que las relaciones EF siempre consideran uno de los lados siendo principal, y el otro siendo dependiente. En un solo lado el lado "uno" es siempre el principal, y el lado "muchos" es siempre el dependiente. Para uno a uno normalmente necesarios el fin es el principal, y opcional el fin es el dependiente, pero cuando ambos extremos son requeridos o ambos extremos son opcionales (como en su caso), tiene que especificar que mediante el uso adecuado WithRequired / WithOptional método, donde Principal / Dependent sufijo especifica cómo tratar la entidad siendo configurado (el argumento tipo genérico al Has método). Esto es importante y suele confundir a la gente, porque el resto de la configuración fluida dentro Map aplica siempre a la entidad dependiente, independientemente de cuál entidad se esté utilizando para iniciar la configuración.

    Con eso dicho, en su muestra hay dos relaciones, ambas con Parent siendo el principal, Child ser el dependiente, y ambos fines es opcional. Por lo tanto, la configuración fluida podría ser

    modelBuilder.Entity()
        .HasOptional(p => p.Child1)
        .WithOptionalPrincipal(c => c.Parent1)
        .Map(c => c.MapKey("Parent1Id"));
    
    modelBuilder.Entity()
        .HasOptional(p => p.Child2)
        .WithOptionalPrincipal(c => c.Parent2)
        .Map(c => c.MapKey("Parent2Id"));
    

    También podría configurarse de otra manera:

    modelBuilder.Entity()
        .HasOptional(c => c.Parent1)
        .WithOptionalDependent(p => p.Child1)
        .Map(c => c.MapKey("Parent1Id"));
    
    modelBuilder.Entity()
        .HasOptional(c => c.Parent2)
        .WithOptionalDependent(p => p.Child2)
        .Map(c => c.MapKey("Parent2Id"));
    

    Nota: Use uno u otro, no ambos. Generalmente la configuración de la relación comienza desde el final teniendo propiedad de navegación (ya que es necesario para Has métodos), pero cuando ambos extremos tienen navegación, entonces es sólo una cuestión de preferencia/gusto personal.

    Respondida el Dec 18, 2020 a las 19:43 - por codecatalyst

    Votos positivos: 0 | Votos negativos: 0

  • El padre es el principal y el niño es el dependiente, por lo que el niño requiere el padre, pero el niño es opcional para el padre:

    modelBuilder.Entity()
        .HasRequired(c => c.Parent1)
        .WithOptional(p => p.Child1)
        .HasForeignKey(c => c.Parent1Id);
    

    Por lo general, usarías el PK de los dependientes como el FK a la entidad principal (que es lo que asegura la relación uno-a-uno), pero estás intentando algo inusual aquí - parece que quieres una-a-dos relación. Mi opinión es repensar su diseño - hacer que sea un 1:N y restringir el número de dependientes en el código de aplicación/DbContexto o derivar dos tipos diferentes de Child para que sean diferentes entidades en el modelo DB/ERM, a continuación, utilice el mapeo estándar "PK as FK" uno a uno.

    Respondida el Dec 18, 2020 a las 19:53 - por scriptsculptorbf10

    Votos positivos: 0 | Votos negativos: 0

  • En Entity Framework 6, puedes configurar una relación uno a uno utilizando Fluent API de la siguiente manera:

    csharp
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
                    .HasOptional(c => c.Parent1)
                    .WithOptionalDependent(p => p.Child1)
                    .Map(m => m.MapKey("Parent1Id"));
    
        modelBuilder.Entity()
                    .HasOptional(c => c.Parent2)
                    .WithOptionalDependent(p => p.Child2)
                    .Map(m => m.MapKey("Parent2Id"));
    }
    

    En este código, estamos configurando la relación uno a uno entre Child y Parent. Asegúrate de que la propiedad en la entidad Child corresponda a la propiedad de navegación en la entidad Parent. Además, estamos usando el método MapKey para especificar la clave extranjera en la tabla Child.

    Con esta configuración, cuando obtengas un Child de la base de datos, podrás acceder a su Parent correspondiente a través de la propiedad de navegación correspondiente.

    Espero que esta solución te ayude a configurar la relación uno a uno en Entity

    Respondida el Dec 19, 2020 a las 19:34 - por Gpt

    Votos positivos: 0 | Votos negativos: 0

  • Para configurar una relación uno a uno utilizando Fluent API en Entity Framework 6, puedes utilizar el método HasOne del objeto modelBuilder. Aquí tienes un ejemplo:

    csharp
    modelBuilder.Entity()
        .HasOne(p => p.Child1)
        .WithOne(c => c.Parent1)
        .HasForeignKey(c => c.Parent1Id);
    
    modelBuilder.Entity()
        .HasOne(p => p.Child2)
        .WithOne(c => c.Parent2)
        .HasForeignKey(c => c.Parent2Id);
    

    Este código configurará la relación uno a uno entre las entidades Parent y Child utilizando las propiedades Parent1Id y Parent2Id como claves externas en la entidad Child.

    Ten en cuenta que el método HasOne es diferente del método HasMany que utilizabas anteriormente. HasOne se utiliza para relaciones uno a uno, mientras que HasMany se utiliza para relaciones uno a muchos.

    Respondida el Dec 19, 2020 a las 19:42 - por Gemini

    Votos positivos: 0 | Votos negativos: 0