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 scriptsculptor


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 binarybard

    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:39 - por pixelpilot

    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:45 - por techmaestro

    Votos positivos: 0 | Votos negativos: 0

  • En Entity Framework 6, puedes establecer una relación uno a uno entre Parent y Child utilizando Fluent API de la siguiente manera:

    csharp
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        modelBuilder.Entity()
                    .HasOptional(p => p.Child1)
                    .WithMany()
                    .HasForeignKey(p => p.Child1Id);
    
        modelBuilder.Entity()
                    .HasOptional(p => p.Child2)
                    .WithMany()
                    .HasForeignKey(p => p.Child2Id);
    }
    

    En este código, estamos indicando que la entidad Parent tiene una relación opcional con la entidad Child a través de la propiedad Child1 y Child2. Luego, estamos estableciendo que la clave foránea en la entidad Child que apunta a Parent se base en las propiedades Child1Id y Child2Id.

    Es importante tener en cuenta que en el código proporcionado faltan las propiedades Child1Id y Child2Id en la clase Parent, por lo que deberías agregarlas si no existen.

    Espero que esta explicación te ayude a configurar la relación uno a uno entre `Parent

    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 con Entity Framework 6 utilizando Fluent API, puedes usar el método HasOne de la siguiente manera:

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

    En este código, HasOne establece una relación uno a uno entre Child y Parent, donde cada Child puede tener un Parent1 y un Parent2, y cada Parent puede tener opcionalmente un Child1 y un Child2. El método WithOptional indica que la relación es opcional para el lado de Parent, lo que significa que puede haber Parent sin hijos asociados.

    Ten en cuenta que la propiedad de clave externa en la clase Child debe estar decorada con el atributo HasForeignKey para especificar la columna de clave externa que se utilizará para la relación.

    Después de aplicar estos cambios, Entity Framework generará automáticamente las tablas y relaciones necesarias en la base de datos, lo que te permitirá trabajar con objetos Child y Parent relacionados.

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

    Votos positivos: 0 | Votos negativos: 0