7

Tengo una clase de contenido que debería poder tener un parentId para herencia pero también quiero que tenga una lista de contenido secundario que no es nada para hacer con este árbol de herencia.Entity Framework Code First Class con padres e hijos del mismo tipo que su propia clase

Básicamente quería una tabla de enlaces como ChildContentRelationship con Id's para parentContent y childContent en ella y la clase Content tendría una lista de ChildContentRelationship.

Esto ha causado muchos errores.

Aquí es waht en cierto modo me quiero hacer

public class Content 
{ 
    public int Id { get; set; } 

    public int? ParentContentId { get; set; } 
    public virtual Content ParentContent { get; set; } 

    public string Name { get; set; } 

    public int ContentTypeId { get; set; } 
    public virtual ContentType ContentType { get; set; } 

    public virtual ICollection<Property> Properties { get; set; } 

    public virtual ICollection<ChildContentRelationship> ChildContent { get; set; } 
} 

¿Cómo podría configurar esto en EF?

+0

¿Qué versión de Entity Framework está utilizando y qué tipo de enfoque (db-first, model-first, code-first)? ¿Y por qué quieres una tabla de enlaces? ¿No tienes una relación de uno a varios, * un * padre y * muchos * hijos? – Slauma

+0

EF 4.1 +, Código primero. Es por este ParentContentId. Ver Quiero que el contenido pueda tener un padre para heredar cualquier propiedad del esquema de tipo de contenido de los padres. Pero también quiero que una parte del contenido tenga una referencia a otro contenido que no está en esta jerarquía de árbol.Esto es para que pueda procesar contenido infantil, como controles. Podría nombrarlo como controles y tener un control tener un ContentId, supongo. –

+0

"Código Primero" ya estaba en el título, estúpido por mí, no lo noté, lo siento. – Slauma

Respuesta

18

No estoy seguro si entiendo su modelo correctamente. Discutamos las opciones.

Por un momento omito esta entidad adicional ChildContentRelationship y supongo que la colección ChildContent es del tipo ICollection<Content>.

  • Opción 1:

    Asumo que ParentContent es la propiedad inversa de ChildContent. Significaría que si tiene un Content con Id = x y este Contenido tiene un ChildContent con Id = y entonces el ChildContents ParentContentId siempre debe ser x. Esto solo sería una asociación única y ParentContent y ChildContent son los puntos finales de esta misma asociación.

    La asignación para esta relación puede crearse con anotaciones de datos ...

    [InverseProperty("ParentContent")] 
    public virtual ICollection<Content> ChildContent { get; set; } 
    

    ... o con la API de Fluido:

    modelBuilder.Entity<Content>() 
        .HasOptional(c => c.ParentContent) 
        .WithMany(c => c.ChildContent) 
        .HasForeignKey(c => c.ParentContentId); 
    

    creo que esto no es lo que quiere ("... no tiene nada que ver con ..."). Considera renombrar tus propiedades de navegación. Si alguien lee Parent... y Child..., muy probablemente asuma que construye un par de propiedades de navegación para la misma relación.

  • Opción 2:

    ParentContent no es la propiedad inversa de ChildContent lo que significaría que en realidad tiene dos relaciones independientes y el segundo punto final de ambas relaciones no se expone en la clase del modelo.

    El mapeo para ParentContent se vería así:

    modelBuilder.Entity<Content>() 
        .HasOptional(c => c.ParentContent) 
        .WithMany() 
        .HasForeignKey(c => c.ParentContentId); 
    

    WithMany() sin parámetros indica que el segundo punto final no es una propiedad de la clase del modelo, sobre todo, no es ChildContent.

    Ahora, la pregunta sigue siendo: ¿A qué tipo de relación pertenece ChildContent?¿Es una relación de uno a muchos o es una relación de muchos a muchos?

    • Opción 2a

      Si un Content se refiere a otros ChildContent s y no puede haber un segundo Content que se refieren a los mismos ChildContent s (los hijos de un Content son único, por lo para hablar) entonces tienes una relación de uno a muchos. (Esto es similar a una relación entre un pedido y artículos de la orden: una posición de pedido sólo puede pertenecer a un orden específico.)

      El mapeo para ChildContent se vería así:

      modelBuilder.Entity<Content>() 
          .HasMany(c => c.ChildContent) 
          .WithOptional(); // or WithRequired() 
      

      tendrá una columna adicional de clave externa en la tabla Content en su base de datos que pertenece a esta asociación pero que no tiene una propiedad FK correspondiente en la clase de entidad.

    • Opción 2b

      Si muchos Content s pueden hacer referencia a las mismas ChildContent s entonces usted tiene una relación de muchos a muchos. (Esto es similar a una relación entre un usuario y los roles: No puede haber muchos usuarios dentro del mismo papel y un usuario puede tener muchos papeles.)

      El mapeo para ChildContent se vería así:

      modelBuilder.Entity<Content>() 
          .HasMany(c => c.ChildContent) 
          .WithMany() 
          .Map(x => 
          { 
           x.MapLeftKey("ParentId"); 
           x.MapRightKey("ChildId"); 
           x.ToTable("ChildContentRelationships"); 
          }); 
      

      Esta asignación creará una tabla de combinación ChildContentRelationships en la base de datos pero no necesita una entidad correspondiente para esta tabla.

    • Opción 2c

      Sólo en el caso de que la relación de muchos a muchos tiene más propiedades, además de las dos teclas (ParentId y ChildId) (por ejemplo, algo así como CreationDate o RelationshipType o ...) habría que introducir una nueva entidad ChildContentRelationship en su modelo:

      public class ChildContentRelationship 
      { 
          [Key, Column(Order = 0)] 
          public int ParentId { get; set; } 
          [Key, Column(Order = 1)] 
          public int ChildId { get; set; } 
      
          public Content Parent { get; set; } 
          public Content Child { get; set; } 
      
          public DateTime CreationDate { get; set; } 
          public string RelationshipType { get; set; } 
      } 
      

      Ahora su clase Content tendría una colección de ChildContentRelationship s:

      public virtual ICollection<ChildContentRelationship> ChildContent 
          { get; set; } 
      

      Y tiene dos uno-a-muchos:

      modelBuilder.Entity<ChildContentRelationship>() 
          .HasRequired(ccr => ccr.Parent) 
          .WithMany(c => c.ChildContent) 
          .HasForeignKey(ccr => ccr.ParentId); 
      
      modelBuilder.Entity<ChildContentRelationship>() 
          .HasRequired(ccr => ccr.Child) 
          .WithMany() 
          .HasForeignKey(ccr => ccr.ChildId); 
      

creo que desea cualquiera de las opciones 2a o 2b, pero no estoy seguro.

+2

Gracias por aclarar eso, supongo que estoy buscando la opción 2b, tal vez las necesidades de nombres aclarados. Creo que es un control más realista, por lo que tal vez necesite una clase/diseño diferente. Voy a tratar mañana. –

+1

¡Esta es una respuesta! :) –

Cuestiones relacionadas