EF基础知识小记六(使用Code First建模自引用关系,常用于系统菜单、文件目录等有层级之分的实体)

日常开发中,经常会碰到一些自引用的实体,比如系统菜单、目录实体,这类实体往往自己引用自己,所以我们必须学会使用Code First来建立这一类的模型.

以下是自引用表的数据库关系图:

ok,下面开始介绍从零创建一个Code First版的自引用模型.

1、往目标项目中添加EF包,通过NuGet程序包添加

导入相关的程序集.

2、创建自引用实体类

    public class Category
    {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int CategoryId { get; private set; }
        public string Name { get; set; }
        public int? ParentCategoryId { get; private set; }
        [ForeignKey("ParentCategoryId")]
        public virtual Category ParentCategory { get; set; } 
        public virtual List<Category> Subcategories { get; set; }
        public Category()
        {
            Subcategories = new List<Category>();
        }
    }

3、创建一个数据库上下文,该上下文必须继承DbContext,代码如下:

    public class EF6RecipesContext : DbContext
    {
        public DbSet<Category> Categories { get; set; }
        public EF6RecipesContext() 
            : base("name=EF6RecipeEntities")
        {
        }
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
            modelBuilder.Entity<Category>().HasMany(cat => cat.Subcategories).WithOptional(cat => cat.ParentCategory);
        }
    }

4、截至这一步,分析下代码,典型的目录实体,从实体类可以看出该实体拥有单个父类型、子类型集合,这里比较特殊的是,这里的父类型和子类型都是自己,也就是自引用.注意:一个没有付类型的实体,该实体就是整个继承类型的最顶端.

5、编写测试代码:

        static void Main(string[] args)
        {
            Example();
        }
        static void Example()
        {
            using (var context = new EF6RecipesContext())
            {
                var first = new Category { Name = "第一级菜单" };
                var second = new Category { Name = "第二级菜单" };
                first.Subcategories.Add(second);
                second = new Category { Name = "第二级菜单" };
                first.Subcategories.Add(second);
                second = new Category { Name = "第二级菜单" };
                first.Subcategories.Add(second);
                var top = new Category { Name = "顶级菜单" };
                top.Subcategories.Add(first);
                context.Categories.Add(top);
                context.SaveChanges();
            }
            using (var context = new EF6RecipesContext())
            {
                var roots = context.Categories.Where(c => c.ParentCategory == null);
                roots.ToList().ForEach(root => Print(root, 0));
            }
            Console.ReadKey();
        }
        static void Print(Category cat, int level)
        {
            StringBuilder sb = new StringBuilder();
            Console.WriteLine("{0}{1}", sb.Append(' ', level).ToString(), cat.Name);
            cat.Subcategories.ForEach(child => Print(child, level + 1));//递归,直到最后遍历的节点没有子节点集合,则跳出递归循环
        }

简单解释下测试代码的逻辑:

(1)、从所有的节点中获取没有父节点的节点,该节点为顶级节点

(2)、然后通过递归将该顶级节点下面的所有的子节点全部遍历出来,每当递归到的节点含有子节点集合,则递归的深度加1.当一个继承链遍历完毕,继续遍历第二个继承链.

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏更流畅、简洁的软件开发方式

我的数据访问函数库的源代码(三)——返回结构数组

/* 2008 4 25 更新 */ 我的数据访问函数库的源码。整个类有1400行,原先就是分开来写的,现在更新后还是分开来发一下吧。 第三部分:返回结构 ...

2086
来自专栏木宛城主

SharePoint CAML In Action——Part II

在SharePoint中,相对于Linq to SharePoint而言,CAML是轻量化的。当然缺点也是显而易见的,"Hard Code"有时会让你抓狂。在实...

1995
来自专栏chenssy

【死磕Sharding-jdbc】---group by结果合并(2)

在sharding-jdbc源码之group by结果合并(1)中主要分析了sharding-jdbc如何在GroupByStreamResultSetMerg...

1052
来自专栏魂祭心

原 荐 NEO VM原理及其实现

4248
来自专栏菩提树下的杨过

温故而知新:c#中的特性(attribute)

特性(Attribute)是微软在.Net中自创的一种新技术,对于很多初学者来讲,特性一直是一块难啃的骨头。 既然弄不懂,那我们就暂时绕过它吧,回想一下我们在写...

2039
来自专栏草根专栏

使用xUnit为.net core程序进行单元测试(中)

第一部分: https://cloud.tencent.com/developer/article/1019835

2688
来自专栏跟着阿笨一起玩NET

PropertyGrid中的枚举显示为中文

本文转载:http://www.cnblogs.com/yank/archive/2011/09/17/2179598.html

1372
来自专栏张善友的专栏

Dynamite动态排序库

易于使用和高性能动态排序库支持类似 SQL 语法和嵌套/复杂的表达式,使用 System.Linq.Expression 动态生成快速比较器。 使用此库就可以使...

22510
来自专栏GreenLeaves

SQL学习之高级数据过滤

一、高级数据过滤之IN操作符 IN 操作符用来指定条件范围,范围中的每个条件都可以进行匹配。IN取一组由逗号分隔、括在圆括号中的合法值。代码如下: select...

2185
来自专栏草根专栏

使用xUnit为.net core程序进行单元测试(2)

下面有一点点内容是重叠的.... String Assert 测试string是否相等: [Fact] public void ...

5457

扫码关注云+社区

领取腾讯云代金券