使用 Entity Framework 7 代码优先定义自引用外键关系
Defining Self Referencing Foreign-Key-Relationship Using Entity Framework 7 Code First
我有一个 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);
我遵循了 here and here 提出的解决方案,但收到一条错误消息:
Introducing FOREIGN KEY constraint 'FK_ArticleComment_ArticleComment_ArticleCommentParentId' on table 'ArticleComment' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints.
Could not create constraint or index. See previous errors.
首先我虽然通过设置 OnDelete(DeleteBehavior.Restrict)
这会消失,但问题仍然存在,我也尝试使用数据注释 [ForeignKey("ArticleCommentParentId")]
正如你可以在ArticleComment
定义,但没有用,对此我将不胜感激。
我简化了 class(删除外键支持字段)并且有效。
这可能是您的 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();
}
}
}
您没有正确建模您的实体。每个评论都需要一个 Set 回复,它们也是 ArticleComment 类型,并且每个回复都是指向其父项的回复(注意添加的 ICollection Replies 属性):
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 足够智能,可以理解这种关系。
我有一个 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);
我遵循了 here and here 提出的解决方案,但收到一条错误消息:
Introducing FOREIGN KEY constraint 'FK_ArticleComment_ArticleComment_ArticleCommentParentId' on table 'ArticleComment' may cause cycles or multiple cascade paths. Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify other FOREIGN KEY constraints. Could not create constraint or index. See previous errors.
首先我虽然通过设置 OnDelete(DeleteBehavior.Restrict)
这会消失,但问题仍然存在,我也尝试使用数据注释 [ForeignKey("ArticleCommentParentId")]
正如你可以在ArticleComment
定义,但没有用,对此我将不胜感激。
我简化了 class(删除外键支持字段)并且有效。
这可能是您的 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();
}
}
}
您没有正确建模您的实体。每个评论都需要一个 Set 回复,它们也是 ArticleComment 类型,并且每个回复都是指向其父项的回复(注意添加的 ICollection Replies 属性):
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 足够智能,可以理解这种关系。