文章内容

2017/1/3 10:34:44,作 者: 黄兵

Entity Framework一对多关系

要在数据库中配置一对多关系,我们可以依赖EF约定,或者可以使用数据注解/fluent API来显式创建关系。接下来我以网站上常见的评论与回复的例子来说明一对多关系。一个评论可能有多个回复,象下面这样:


下面是评论的数据表的定义:

 public partial class Comment
    {
        public int Id { get; set; }
        public string Body { get; set; }
        public DateTime CreationTime { get; set; }
        public string Name { get; set; }
        public string Mail { get; set; }
        public string Phone { get; set; }
        public bool State { get; set; }

        public int BlogId { get; set; }
        public int? PosterId { get; set; }
        public virtual Blog Blog { get; set; }
        public virtual User User { get; set; }
        public virtual ICollection<CommentReply> CommentReply { get; set; }
    }

看一下评论回复的数据表定义:

public class CommentReply
    {
        public int Id { get; set; }
        public string ReplyBody { get; set; }
        public DateTime DateTime { get; set; }
        public int ParentId { get; set; }
        public string Url { get; set; }       
    }

一个评论有多个回复,这句话就表明了Comment对象应该有一个CommentReply的集合,因此,我们要给Comment类新加入一个属性,为了避免潜在的null引用异常可能性,当Comment对象创建时,我们使用HashSet的T集合类型实例创建一个新的集合实例,如下所示:

 public partial class Comment
    {
        public Comment()
        {
            CommentReply = new HashSet<CommentReply>();
        }

        public int Id { get; set; }
        public string Body { get; set; }
        public DateTime CreationTime { get; set; }
        public string Name { get; set; }
        public string Mail { get; set; }
        public string Phone { get; set; }
        public bool State { get; set; }

        public int BlogId { get; set; }
        public int? PosterId { get; set; }
        public virtual Blog Blog { get; set; }
        public virtual User User { get; set; }
        public virtual ICollection<CommentReply> CommentReply { get; set; }
    }

你会注意到当我定义CommentReply属性时使用了virtual关键字,当为一个评论查询有什么回复的时候,该关键字允许我们使用懒加载(lazy loading),也就是说当你尝试访问Comment的CommentReply属性时,EF会动态地从数据库加载CommentReply对象到该集合中。懒加载,顾名思义,就是首次不会执行查询来填充CommentReply属性,而是在请求它时才会加载数据。还有另一加载相关数据的方式叫做预先加载(eager loading)。通过预先加载,在访问CommentReply属性之前,CommentReply就会主动加载。现在我们假设要充分使用懒加载功能,所以这里使用了virtual关键字。这里有意思的是,在支付方法CommentReply类中并没有包含Comment的Id属性,这是作为数据库开发者必须要做的一些事,但在EF的世界中,我们有很大的灵活性来忽略这个属性,由于当我们看支付方式的时候可能没有合理的业务原因来知道该评论的Id,所以我们可以忽略该属性。这个例子中,我们只想在Comment的上下文中了解他的评论,并不把它们分离开作为独立对象。

 //评论与回复之间一对多关系
            modelBuilder.Entity<Comment>()
                .HasMany(c => c.CommentReply)
                .WithRequired()
                .HasForeignKey(c => c.ParentId)
                .WillCascadeOnDelete(false);

上面的代码对于关系的定义很经典。HasMany方法告诉EF在   CommentCommentReply类之间有一个一对多的关系。WithRequired方法表明链接在CommentReply属性上的Comment是必须的,换言之,CommentReply对象不是独立的对象,必须要链接到一个Comment。HasForeignKey方法会识别哪一个属性会作为链接。

分享到:

发表评论

评论列表