实体框架6和集合

时间:2013-12-17 04:35:05

标签: c# entity-framework

我正在开发我的第一个实体框架应用程序。我正在使用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)

SOLUTION:

感谢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!我认为这也是我很多挫折的根源。

2 个答案:

答案 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]注释。