使用實體框架7代碼優先定義自引用外鍵關係

ef-fluent-api entity-framework-core

我有一個ArticleComment實體,如下所示:

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


}

我想以這樣的方式定義外鍵關係,即一個註釋可以有很多回复或子,我試圖使用流暢的API創建關係,如下所示:

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

我按照這里這裡提出的解決方案,但我收到錯誤消息:

在'ArticleComment'表上引入FOREIGN KEY約束'FK_ArticleComment_ArticleComment_ArticleCommentParentId'可能會導致循環或多個級​​聯路徑。指定ON DELETE NO ACTION或ON UPDATE NO ACTION,或修改其他FOREIGN KEY約束。無法創建約束或索引。查看以前的錯誤。

首先我通過設置OnDelete(DeleteBehavior.Restrict)這將消失,但問題仍然存在,我也嘗試使用數據註釋[ForeignKey("ArticleCommentParentId")]因為您可以看到ArticleComment的註釋代碼定義,但它不起作用,我會欣賞這一點。

一般承認的答案

您沒有正確建模您的實體。每個評論都需要一回复,這些回復也是ArticleComment類型,並且每個回复都是指向其父回复的回复 (請注意添加的ICollection回复屬性 ):

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

...和流暢的映射:

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

通過上面的設置,您將獲得一個開放式樹結構。

編輯:使用屬性,您只需要裝飾ParentArticleComment屬性。考慮到在這種情況下EF將按慣例解決所有關係。

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

對於集合屬性,EF非常聰明,可以理解這種關係。


熱門答案

我簡化了類(刪除外鍵支持字段)並且它可以工作。
這可能是你的EF版本的問題(我剛剛安裝了它,但實際上我認為我正在使用rc1,但我不確定因為我有幾個依賴性問題)或者它可能是你的模型。
無論如何,這個來源工作正常

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


Related

許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow
許可下: CC-BY-SA with attribution
不隸屬於 Stack Overflow