我正在开发我的第一个实体框架应用程序。我正在使用EF vesion 6(来自Nuget)和.net 4.0。但是,对我来说,我遇到了一些困难,对我来说,它似乎应该非常简单。我在互联网上发现了许多相互矛盾的建议和解决方案,但在花了几天时间尝试解决问题之后,我真的很困惑,并且质疑我对实体框架的一些基本理解。我想要做的是:创建一个简单的相关实体集合,并在从父项中删除它们时自动删除它们。
以下是我在vanilla C#中对此进行建模的方法。与Microsoft示例一致,假设我们有两个类,Post和Tag,如下所示:
public class Post
{
public string Name { get; set; }
public string Author { get; set; }
public ICollection<Tag> Tags { get; set; }
}
public class Tag
{
public string Text { get; set; }
// Possibly other properties here
}
然后,添加标记就像myPost.Tags.Add(myTag)
一样简单,删除标记就像myPost.Tags.Remove(myTag)
一样简单。
现在进入实体框架的一面:我看着那个并想到了“外键,当然!”但是我添加了一个FK有很多问题:标签在从帖子中删除时不会从数据库中删除,myPost.Tags
从数据库加载时会有0个元素,尽管SQL资源管理器显示了PostId价值是正确的等等。我用一堆技巧搞砸了,比如将Tag.PostId
标记为键,手动删除标签,实际上将标签作为DbSet添加到上下文中,手动设置myTag.Post = null;
(I尝试使用Lazy加载启用和禁用,以实现它的价值 - 尽管如果可能的话我想保持关闭
现在(在很大程度上要归功于看似矛盾和过于复杂的例子),我很困惑并迷失了。有人能告诉我我应该如何在EF中建立这种关系吗? (顺便说一句,我正在使用Code First)
感谢Moho,我想出了这个结构,它完全符合我的要求:
public class Post
{
public int Id { get; set; }
public string Name { get; set; }
public string Author { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
public Post()
{
Tags = new HashSet<Tag>();
}
}
public class Tag
{
[Key, Column(Order=1), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Text { get; set; }
// Possibly other properties here
public virtual Post Post { get; set; }
[Key, Column(Order=2)]
public virtual int PostId { get; set; }
}
public class TestContext : DbContext
{
public DbSet<Post> Posts { get; set; }
}
从Tag
的标签集合中删除Post
后,实体框架会为标记发出DELETE,如此处所述(#2):http://www.kianryan.co.uk/2013/03/orphaned-child/
同样,向帖子添加标签将自动发出INSERT并设置FK关系。
有一点需要注意:确保使用virtual
!我认为这也是我很多挫折的根源。
答案 0 :(得分:2)
同时尝试定义Tag
方面的关系,指定每个Tag
与单个Post
相关,并且是必需的。
将所需的导航属性添加到Post
中的Tag
:
public class Tag
{
// you need an ID
public int Id { get; set; }
public string Text { get; set; }
[Required]
public virtual Post Post { get; set; }
}
或者,如果您确实不想添加导航属性,则可以使用Fluent API:
modelBuilder.Entity<Post>().HasMany( p => p.Tags ).WithRequired();
答案 1 :(得分:1)
这可能是线索的坏死,但我不会让代表发表评论。以下不会做你需要的吗?
public class Tag
{
[Key, Column(Order=1), DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Text { get; set; }
// Possibly other properties here
public int PostId { get; set; }
[ForeignKey("PostId")]
public virtual Post Post { get; set; }
}
PostId从数据库加载,然后用作外键(通过注释)进入Post类。帖子是虚拟的,没有别的。您也可以使用基本的[Key]注释。