Definición de la referencia de clave externa de referencia automática mediante Entity Framework 7 Código primero

ef-fluent-api entity-framework-core

Pregunta

Tengo una entidad ArticleComment como se puede ver a continuación:

public class ArticleComment
 {
    public int ArticleCommentId { get; set; }
    public int? ArticleCommentParentId { get; set; }

    //[ForeignKey("ArticleCommentParentId")]
    public virtual ArticleComment Comment { get; set; }
    public DateTime ArticleDateCreated  { get; set; }
    public string ArticleCommentName { get; set; }
    public string ArticleCommentEmail { get; set; }
    public string ArticleCommentWebSite { get; set; }
    public string AricleCommentBody { get; set; }

    //[ForeignKey("UserIDfk")]   
    public virtual ApplicationUser ApplicationUser { get; set; }
    public Guid? UserIDfk { get; set; }

    public int ArticleIDfk { get; set; }
    //[ForeignKey("ArticleIDfk")]   
    public virtual Article Article { get; set; }


}

Quiero definir una relación de clave externa de tal manera que un comentario pueda tener muchas respuestas o elementos secundarios. He intentado crear la relación utilizando una API fluida como esta:

public class ArticleComment
 {
    public int ArticleCommentId { get; set; }
    public int? ArticleCommentParentId { get; set; }

    //[ForeignKey("ArticleCommentParentId")]
    public virtual ArticleComment Comment { get; set; }
    public DateTime ArticleDateCreated  { get; set; }
    public string ArticleCommentName { get; set; }
    public string ArticleCommentEmail { get; set; }
    public string ArticleCommentWebSite { get; set; }
    public string AricleCommentBody { get; set; }

    //[ForeignKey("UserIDfk")]   
    public virtual ApplicationUser ApplicationUser { get; set; }
    public Guid? UserIDfk { get; set; }

    public int ArticleIDfk { get; set; }
    //[ForeignKey("ArticleIDfk")]   
    public virtual Article Article { get; set; }


}

Seguí la solución que se propuso aquí y aquí , pero aparece un mensaje de error:

La introducción de la restricción FOREIGN KEY 'FK_ArticleComment_ArticleComment_ArticleCommentParentId' en la tabla 'ArticleComment' puede provocar ciclos o varias rutas en cascada. Especifique ON DELETE NO ACTION o ON UPDATE NO ACTION, o modifique otras restricciones FOREIGN KEY. No se pudo crear restricción o índice. Ver errores anteriores.

Primero pensé que al establecer OnDelete(DeleteBehavior.Restrict) esto desaparecería, pero el problema persiste, también he intentado usar la anotación de datos [ForeignKey("ArticleCommentParentId")] como puede ver el código comentado en ArticleComment definición, pero no funcionó, apreciaría algo en esto.

Respuesta aceptada

No estás modelando correctamente tu entidad. Cada comentario necesita un conjunto de respuestas, que también son del tipo ArticleComment, y cada una de esas respuestas son las que apuntan a su padre ( tenga en cuenta la propiedad de respuestas ICollection agregada):

  public class ArticleComment
     {
        public ArticleComment()
        {
            Replies = new HashSet<ArticleComment>();
        }

        public int ArticleCommentId { get; set; }
        public int? ParentArticleCommentId { get; set; }
        public virtual ArticleComment ParentArticleComment{ get; set; }
        public virtual ICollection<ArticleComment> Replies { get; set; }

        //The rest of the properties omitted for clarity...
    }

... y el mapeo fluido:

  public class ArticleComment
     {
        public ArticleComment()
        {
            Replies = new HashSet<ArticleComment>();
        }

        public int ArticleCommentId { get; set; }
        public int? ParentArticleCommentId { get; set; }
        public virtual ArticleComment ParentArticleComment{ get; set; }
        public virtual ICollection<ArticleComment> Replies { get; set; }

        //The rest of the properties omitted for clarity...
    }

Con la configuración anterior se obtiene una estructura de árbol abierta.

EDITAR: usando atributos, solo necesita decorar la propiedad ParentArticleComment. Tenga en cuenta que en este caso EF resolverá todas las relaciones por convención.

  public class ArticleComment
     {
        public ArticleComment()
        {
            Replies = new HashSet<ArticleComment>();
        }

        public int ArticleCommentId { get; set; }
        public int? ParentArticleCommentId { get; set; }
        public virtual ArticleComment ParentArticleComment{ get; set; }
        public virtual ICollection<ArticleComment> Replies { get; set; }

        //The rest of the properties omitted for clarity...
    }

Para las propiedades de colección, EF es lo suficientemente inteligente como para entender la relación.


Respuesta popular

Simplifiqué la clase (eliminando campos de soporte de clave externa) y funciona.
Podría ser un problema de su versión EF (acabo de instalarlo pero en realidad creo que estoy usando rc1 pero no estoy seguro porque tuve varios problemas de dependencia) o podría ser su modelo.
De todos modos, esta fuente funciona bien.

public class ArticleComment
{
    public int ArticleCommentId { get; set; }

    public virtual ArticleComment Comment { get; set; }
    public DateTime ArticleDateCreated { get; set; }
    public string ArticleCommentName { get; set; }
    public string ArticleCommentEmail { get; set; }
    public string ArticleCommentWebSite { get; set; }
    public string AricleCommentBody { get; set; }
}

class Context : DbContext
{
    public Context(DbContextOptions dbContextOptions) : base(dbContextOptions)
    {}

    public DbSet<ArticleComment> Comments { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        modelBuilder.Entity<ArticleComment>()
            .HasOne(p => p.Comment)
            .WithMany();

    }
}

static class SampleData
{
    public static void Initialize(Context context)
    {
        if (!context.Comments.Any())
        {
            var comment1 = new ArticleComment()
            {
                AricleCommentBody = "Article 1"
            };

            var comment2 = new ArticleComment()
            {
                AricleCommentBody = "Article 2 that referes to 1",
                Comment = comment1
            };

            context.Comments.Add(comment2);
            context.Comments.Add(comment1);

            context.SaveChanges();
        }
    }
}



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é