日常开发中,经常会碰到一些自引用的实体,比如系统菜单、目录实体,这类实体往往自己引用自己,所以我们必须学会使用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. 不用快捷键就能使用Eclipse的自动完成功能

    偶然间看到了这个,或许有和我一样不喜欢按 alt-/ 兄弟用得上.不用老去按那个 alt-/ 了,还是方便不少.         打开 Eclipse -> Window -> Perfe ...

  2. post异步请求

    //创建url NSURL *url = [[NSURL alloc] initWithString:@"http://api.hudong.com/iphonexml.do"]; ...

  3. android插件化简述

    2015年是Android插件化技术突飞猛进的一年,随着业务的发展各大厂商都碰到了Android Native平台的瓶颈: 从技术上讲,业务逻辑的复杂导致代码量急剧膨胀,各大厂商陆续出到65535方法 ...

  4. [翻译Joel On Software]选择一门语言/Choosing a language

    Joel on Software Choosing a language 选择一门语言 by Joel Spolsky Sunday, May 05,2002 Why do developerscho ...

  5. REST格式

    首先要明确一点:REST 实际上只是一种设计风格,它并不是标准.(所以你可以看到网上一大堆的各种最佳实践,设计指南,但是没有人说设计标准).aisuhua/restful-api-design-ref ...

  6. 酒店订房系统:如何使用mysql来确定一个时间段内的房间都是可订的

    需要解决的问题: 假设一个用户选择了日期范围来进行订房,例如:2014-04-25至2014-04-30 ,那么现在问题就出现,你必须要确认在这个时间段内某个房间是否都是有房间的,如果没有那么当然不能 ...

  7. Android-fragment的替换-V4支持包

    昨天写的这几篇博客,Android-fragment简介-fragment的简单使用,Activity-fragment-ListView展示,Android-fragment生命周期,Android ...

  8. 手动处理TFS数据仓库服务和分析服务

    当您需要报告中最新的数据时,当发生错误时,或者在解决了模式冲突之后,您可以手动处理Team Foundation Server(TFS)关系数据库(TFSHStor)或SQLServer Analys ...

  9. Ajax异步请求阻塞情况的解决办法

    最近使用ExtJs4的mvc模式在开发了在线漫画的后台,因为异步请求比较多,有的回应时间长,有点短.我发现在多次并发的情况下,会造成阻塞的情况.也就是说如果回应时间长的请求还在进行中,短的请求却被挂起 ...

  10. Asp.Net Web Api中使用Swagger

    关于swagger 设计是API开发的基础.Swagger使API设计变得轻而易举,为开发人员.架构师和产品所有者提供了易于使用的工具. 官方网址:https://swagger.io/solutio ...