日常开发中,经常会碰到一些自引用的实体,比如系统菜单、目录实体,这类实体往往自己引用自己,所以我们必须学会使用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, ));
}
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)、从所有的节点中获取没有父节点的节点,该节点为顶级节点

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

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

  1. EF基础知识小记四(数据库=>模型设计器)

    EF基础知识小记三(设计器=>数据库)介绍了如何创建一个空设计器模型,并如何将模型同步到数据库的表中,本文则主要介绍如何将一个存在的数据库同步到模型设计器中.为了能快速的模拟这个过程,给出一下建 ...

  2. 使用Code First建模自引用关系笔记 asp.net core上使用redis探索(1) asp.net mvc控制器激活全分析 语言入门必学的基础知识你还记得么? 反射

    使用Code First建模自引用关系笔记   原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasR ...

  3. 《Entity Framework 6 Recipes》中文翻译系列 (6) -----第二章 实体数据建模基础之使用Code First建模自引用关系

    2-5 使用Code First建模自引用关系 问题 你的数据库中一张自引用的表,你想使用Code First 将其建模成一个包含自关联的实体. 解决方案 我们假设你有如图2-14所示的数据库关系图的 ...

  4. EF基础知识小记七(拆分实体到多个表以及拆分表到多个实体)

    一.拆分实体到多个表 1.在日常开发中,会经常碰到一些老系统,当客户提出一些新的需求,这些需求需要在原来的表的基础上加一些字段,大多数人会选择通过给原表添加字段的方式来完成这些需求,方法,虽然可行,但 ...

  5. EF基础知识小记五(一对多、多对多处理)

    本文主要讲EF一对多关系和多对多关系的建立 一.模型设计器 1.一对多关系 右键设计器新增关联 导航属性和外键属性可修改 2.多对多关系 右键设计器新增关联 模型设计完毕之后,根据右键设计器根据模型生 ...

  6. EF基础知识小记二

    1.EF的常用使用场景 (1).维护一个已经存在的数据库,VS提供了工具帮助我们把数据库中的表和视图等对象导入到实体框架.        [数据库=>模型(Database First)] (2 ...

  7. EF基础知识小记一

    1.EF等ORM解决方案出现的原因 因为软件开发中分析和解决问题的方法已经接近成熟,然后关系型数据库却没有,很多年来,数据依然是保存在表行列这样的模式里,所以,在面相对象和高度标准化的数据库中产生了一 ...

  8. EF基础知识小记三(设计器=>数据库)

    本文主要介绍通过EF的设计器来同步数据库和对应的实体类.并使用生成的实体上下文,来进行简单的增删查该操作 1.通过EF设计器创建一个简单模型 (1).右键目标项目添加新建项 (2).选择ADO.Net ...

  9. 使用Code First建模自引用关系笔记

    原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasRequired:前者(A)包含后者(B)一个不为 ...

随机推荐

  1. UVaLive 3645 Objective: Berlin (最大流)

    题意:有n个城市,m条航班.已知每条航班的起点和终点,还有每条航班的载客量.出发时间.到达时间.并且要求在任何一个城市(起点.终点除外)都至少要有30分钟的中转时间,求起点到终点的最大客流量. 析:把 ...

  2. (线段树)Mayor's posters --poj -- 2528

    链接: http://poj.org/problem?id=2528 覆盖问题, 要从后往前找, 如果已经被覆盖就不能再覆盖了,否则就可以覆盖 递归呀递归什么时候我才能吃透你 代码: #include ...

  3. SpringMvc中controller之间的方法调用

    方法一, return new ModelAndView("redirect:"+新地址); 方法二, response.sendRedirect(新地址); return nul ...

  4. Oracle实现递归查询

    前几天在开发的过程中遇到一个递归查询的问题,java代码大致是这样的: // 递归得到四级机构对象 public UserManagerDept getuserManagerDeptBy(String ...

  5. hdu 1014

    我:题都看不懂 路人甲:这是随机数分配题目 路人乙:这是求生成元,求mod N的生成元,即生成元与N互质 路人丙:这是根据给出的递推公式算一下 0~ mod-1之间的数是否都有出现过,如果都出现了,那 ...

  6. UT源码+019

    设计三角形问题的程序 输入三个整数a.b.c,分别作为三角形的三条边,现通过程序判断由三条边构成的三角形的类型为等边三角形.等腰三角形.一般三角形(特殊的还有直角三角形),以及不构成三角形.(等腰直角 ...

  7. vux组件简单使用请大佬指点

    一.打开vux项目 我用的是vsCode工具自己找看个人选择,第一次使用请去找vc方便开发使用的插件 二.项目目录及文件,有遮挡部分自行查看文件 三.根据官方文档实现引入插件 通过vux-loader ...

  8. keil小技能随用随定义

    大家都知道在C语言编程时一般都是先定义再使用这个变量的,不允许在语句的后面再定义,但是有时候我们会在KEIL中发现有些人使用变量就在语句后定义,这时我们自己去尝试却发现总是失败,这是为何呢? 原来是我 ...

  9. Docker registry 私有仓库镜像查询、删除、上传、下载 shell

    #Docker官方私有仓库registry #官方只提供了API接口,不方便使用,就写了个shell #docker-registry安装配置http://www.cnblogs.com/elvi/p ...

  10. 微信小程序 Unexpected end of JSON input/Unexpected token o in JSON at position 1

    原因JSON.parse无法识别某些url中的特殊字符,所以报错 mistakes.js中 nextBtn:function(){ var nextData = this.data.dataNextI ...