Definire il referenziamento delle relazioni con le proprie estranee usando il codice di Entity Framework 7

ef-fluent-api entity-framework-core

Domanda

Ho un'entità ArticleComment come puoi vedere qui sotto:

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; }


}

Voglio definire una relazione di chiave esterna in modo tale che un commento possa avere molte risposte o un bambino, ho cercato di creare la relazione usando API fluenti come questa:

builder.Entity<ArticleComment>()
            .HasOne(p => p.Comment)
            .WithMany()
            .HasForeignKey(p => p.ArticleCommentParentId)
            .OnDelete(DeleteBehavior.Restrict)
            .IsRequired(false);

Ho seguito la soluzione proposta qui e qui , ma ricevo un errore con il messaggio:

L'introduzione del vincolo FOREIGN KEY "FK_ArticleComment_ArticleComment_ArticleCommentParentId" nella tabella "ArticleComment" può causare cicli o più percorsi a cascata. Specificare ON DELETE NO ACTION o ON UPDATE NO ACTION o modificare altri vincoli FOREIGN KEY. Impossibile creare vincoli o indici. Vedi errori precedenti.

Prima però impostando OnDelete(DeleteBehavior.Restrict) questo andrebbe via, ma il problema persiste, inoltre ho provato a usare l'annotazione dei dati [ForeignKey("ArticleCommentParentId")] come puoi vedere il codice commentato ArticleComment definizione, ma non ha funzionato, apprezzerei comunque su questo.

Risposta accettata

Non stai modellando correttamente la tua entità. Ogni commento ha bisogno di un Set di risposte, che sono di tipo ArticleComment, e ognuna di quelle risposte sono quelle che puntano al suo genitore (si noti la proprietà di ICollection Replies aggiunta):

  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...
    }

... e la mappatura fluente:

modelBuilder.Entity<ArticleComment>(entity =>
{
    entity
        .HasMany(e => e.Replies )
        .WithOne(e => e.ParentArticleComment) //Each comment from Replies points back to its parent
        .HasForeignKey(e => e.ParentArticleCommentId );
});

Con la configurazione di cui sopra si ottiene una struttura ad albero aperta.

MODIFICA: utilizzando gli attributi è sufficiente decorare la proprietà ParentArticleComment. Tieni conto che in questo caso EF risolverà tutte le relazioni per convenzione.

[ForeignKey("ParentArticleCommentId")]
public virtual ArticleComment ParentArticleComment{ get; set; } 

Per le proprietà di raccolta EF è abbastanza intelligente da comprendere la relazione.


Risposta popolare

Ho semplificato la classe (rimuovendo i campi di supporto delle chiavi esterne) e funziona.
Potrebbe essere un problema della tua versione EF (l'ho appena installata, ma in realtà penso di usare rc1 ma non sono sicuro perché ho avuto diversi problemi di dipendenza) o potrebbe essere il tuo modello.
Ad ogni modo, questa fonte funziona bene

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();
        }
    }
}



Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché