一、简介

Entity Framework是微软的Object Relational Mapper(对象关系映射器),也就是我们平常说的ORM,它可以让应用程序开发者将关系型数据作为业务模型来使用。

Entity Framework分为 DabaBase First、Code First、Model First。本篇主要是结束Code First的一些应用。

  • Database First:这是一种用于已存在数据库模式的方法。使用这种方法,EDM是从数据库模式中生成的,这种方法最适合于使用了已经存在的数据库的应用。
  • Code First:这种方法中,所有的领域模型都是以类的形式编写的。这些类会建立我们的EDM,数据库模式会从这些类中创建。这种方法最适合于那些高度以领域为中心并且领域模型类创建优先的应用程序。这里需要的数据库只是为了这些领域模型的持久化机制。
  • Model First:这种方法和Code First方法很相似,但是这种情况下我们使用了EDM视觉设计器来设计我们的模型。数据库模式和类将会通过这个概念模型生成。该模型将会给我们创建数据库的SQL语句,然后我们可以使用它来创建数据库并连接应用程序。

下面是使用Entity Framework的一些好处:

  • 因为开发者不需要为数据访问编写所有需要的ADO.NET管道代码,因此这可以节省很多开发时间。
  • 我们可以使用更高级的语言(例如C#)来编写所有的数据访问逻辑而不是编写SQL查询和存储过程。
  • 因为数据库表没有高级的关系(如继承),然而领域实体是可以有的,所以业务模型(也就是概念模型)可以使用实体间的关系来适配应用领域。
  • 底层的数据存储可以相对轻松地被取代,因为所有的数据访问逻辑都呈现在应用层而不是数据层。

二、什么是ORM

对象关系映射(Object Relational Mapping,简称ORM)模式是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。

简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

三、搭建Entity FrameWork CodeFirst应用

使用 Entity FrameWork必须引用 EntityFrameWork.DLL 文件,

可以通过VS 工具/NuGet管理器/命令控制台,在出现的命令窗口上输入 Install-Pageage EntityFramework 命令,回车自动安装。

在项目中创建  T_User 类

public class T_User
{
public T_User() { } /// <summary>
/// id
/// </summary>
[Required]
[Key]
public int Id { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Required]
[MaxLength()]
public string UserName { get; set; }
/// <summary>
/// 账号
/// </summary>
[Required]
[MaxLength()]
public string Account { get; set; }
/// <summary>
/// Sex
/// </summary>
[Required]
public int Sex { get; set; }
/// <summary>
/// 密码
/// </summary>
[Required]
[MaxLength()]
[Column("Password", TypeName = "varchar")]
public string Password { get; set; }
/// <summary>
/// 地址
/// </summary>
[MaxLength()]
public string Address { get; set; }
/// <summary>
///
/// </summary>
[MaxLength()]
public string Memo { get; set; }
}

设置配置文件,配置数据库连接串

打开项目目录下的APP.Config,(按照项目的实际情况)因为我的项目是普通的类库,

假如你的项目是Web项目,那就配置在 Web.Config。配置数据库的用户名和密码

 <connectionStrings>
<!-- 假如采用 Window连接方式,则取消注释采用第一个连接串
<add name="DBEntities" connectionString="Server=127.0.0.1;Database=MyDataBase;Integrated Security=SSPI" providerName="System.Data.SqlClient"/>
-->
<add name="DBEntities" connectionString="Server=127.0.0.1;Database=MyDataBase;uid=sa;password=123" providerName="System.Data.SqlClient"/>
</connectionStrings>

添加数据库上下文

接下来我们创建数据库上下文,它是数据库的抽象。目前,我们只有一张表T_User,因而要给该数据库上下文定义一个属性来代表这张表

再者,一张表中一般肯定不止一条数据行,所以我们必须定义一个集合属性,EF使用 DbSet来实现这个目的。

新建 DBEntitys.CS 类文件(类名按照自己的需要),集成 DbContext 类。

在这里,DbContext 是所有基于EF的上下文基类,通过它可以访问到数据库中的所有表。

上面的代码中调用了父类的构造函数,并且传入了一个键值对,键是name,值是 DBEntities,也就是刚刚配置文件的数据库连接串的Name

这个键值对是定义在应用程序的配置文件中的,取决于你的应用程序类型,可能是app.config或者web.config。在我们的 程序中就是App.config

在app.config文件的configuration的节点下(不要在第一个节点下,否则报错)添加:

 public class DBEntitys : DbContext
{
public DBEntitys()
: base("DBEntities")
{ }
public virtual DbSet<T_User> T_User { get; set; }
}

做完上面的时候去以后,这个时候 咱们通过控制台程序去获取上下文对象里的T_User。

 static void Main(string[] args)
{
using (var context = new DBEntitys())
{
context.Database.CreateIfNotExists();//如果数据库不存在时则创建
}
Console.Write("DB has Created!");//提示DB创建成功
Console.Read();
}

打开数据库,你会发现,EF帮我们自动创建了数据库和表

创建数据库的方式有两种:

  1. 下面我们会通过数据库迁移来实现数据库的创建。
  2. 通过EF数据库的API来创建。

四、数据库迁移

随着我们项目的进展,我们的数据库结构也可能发生改变时,我们可以使用EF本身来更新数据库。要使用这项技术,我们必须在项目上启用迁移(migration)。

首先我们把刚刚创建的数据删除。

打开 VS 工具/NubGet包管理器/程序包控制管理台,

1、默认项目选择刚才创建的项目 Entity(按照实际代码所在的项目),然后在窗口中输入 Enable-Migrations,最后按下Enter键即可:

运行该命令后,我们会看到Data项目中多了一个名叫Migrations的文件夹,该文件夹里面有一个类,它指定了迁移配置,通过泛型参数将它连接到我们的数据库上下文。

2、然后在继续在窗口中输入  Add-Migrations migrations,按下Enter键添加一个名为 FirstMigration 的迁移

3、执行   Update-DataBase 命令,更新数据库架构

如果更新数据库存在冲突而不能执行更新,可以添加 -Force强制执行,例如:“Update-Database -Force”

 4、设置自动迁移
每次都通过控制台来进行迁移太过麻烦,可以设置为自动迁移。

打开 Migrations 文件夹下的 Configuration.CS文件,将 构造函数里的 AutomaticMigrationsEnabled=false; 改成 True

执行   Update-DataBase -Force 命令,更新数据库架构
有以下两个参数可以对自动迁移进行设置:
1. AutomaticMigrationsEnabled:获取或设置 指示迁移数据库时是否可使用自动迁移的值。
2. AutomaticMigrationDataLossAllowed:获取或设置 指示是否可接受自动迁移期间的数据丢失的值。如果设置为false,则将在数据丢失可能作为自动迁移一部分出现时引发异常

--------------------------------------------   注意!  ----------------------------------------------------------------------------
默认 Configuration() 方法里只有 AutomaticMigrationsEnabled = true;将 true改为 false,

然后添加 AutomaticMigrationDataLossAllowed = false;

以后再更新模型的时候,直接执行命令 Update-DataBase 命令,更新数据库架构即可。

 internal sealed class Configuration : DbMigrationsConfiguration<Entity.DBEntitys>
{
public Configuration()
{
AutomaticMigrationsEnabled = true;
AutomaticMigrationDataLossAllowed = false;
} protected override void Seed(Entity.DBEntitys context)
{
// This method will be called after migrating to the latest version. // You can use the DbSet<T>.AddOrUpdate() helper extension method
// to avoid creating duplicate seed data.
}
}

 5、数据库回滚

假如我们需要将数据库还原到之前的某个迁移版本,还是可以通过命令完成  Update-DataBase -TargetMigration:MigrationVersion 命令,

MigrationVersion 填写迁移的版本:打开生成的数据库里面有个__MigrationHistory表,选择主键即可。

如果你想回滚一切至空数据库,可以使用 Update-DataBase -TargetMigration:$initialDataBase 命令

五、表属性常见配置

EF Code-First提供了一组DataAnnotation属性,您可以将其应用于您的域类和属性。 DataAnnotation属性覆盖默认的Code-First约定。

System.ComponentModel.DataAnnotations
Key 映射到相关表的主键
Timestamp 不为空的时间戳列
Required 必填
MinLength 最小长度
MaxLength 最大长度,也是设置数据库列的最大长度
StringLength 字符串长度
System.ComponentModel.DataAnnotations.Schema
Table 指定将与该类映射的DB表的名称
Column 指定要与属性映射的列名称和数据类型
ForeignKey 指定导航属性的外键属性
public class T_User
{
public T_User() { } /// <summary>
/// id
/// </summary>
[Required]
[Key]
public int Id { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Required]
[MaxLength()]
public string UserName { get; set; }
/// <summary>
/// 账号
/// </summary>
[Required]
[MaxLength()]
public string Account { get; set; }
/// <summary>
/// Sex
/// </summary>
[Required]
public int Sex { get; set; }
/// <summary>
/// 密码
/// </summary>
[Required]
[MaxLength()]
[Column("Password", TypeName = "varchar")]
public string Password { get; set; }
/// <summary>
/// 地址
/// </summary>
[MaxLength()]
public string Address { get; set; }
/// <summary>
///
/// </summary>
[MaxLength()]
public string Memo { get; set; }
/// <summary>
/// 班级
/// </summary>
public int GradeId { get; set; }
/// <summary>
/// 班级
/// </summary>
[ForeignKey("GradeId")]
public virtual T_Grade T_Grade { get; set; }
}

六、Entity FrameWork 一对多、多对多

在平时的开发工作中,经常有多表查询,表和表之前的关系有单表查询、一对多查询、多对多查询。

1、一对多

例:在学校里有很多学生,每个学生是一个用户,每个用户都所属一个班级。班级和用户是一对多的关系。下面通过 Code First 实现一对多查询

学生类:

public class T_User
{
public T_User() { } /// <summary>
/// id
/// </summary>
[Required]
[Key]
public int Id { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Required]
[MaxLength()]
public string UserName { get; set; }
/// <summary>
/// 账号
/// </summary>
[Required]
[MaxLength()]
public string Account { get; set; }
/// <summary>
/// Sex
/// </summary>
[Required]
public int Sex { get; set; }
/// <summary>
/// 密码
/// </summary>
[Required]
[MaxLength()]
[Column("Password", TypeName = "varchar")]
public string Password { get; set; }
/// <summary>
/// 地址
/// </summary>
[MaxLength()]
public string Address { get; set; }
/// <summary>
///
/// </summary>
[MaxLength()]
public string Memo { get; set; }
/// <summary>
/// 班级
/// </summary>
public int GradeId { get; set; }
/// <summary>
/// 班级
/// </summary>
[ForeignKey("GradeId")]
public virtual T_Grade T_Grade { get; set; }
}

班级类:

/// <summary>
/// 班级表
/// </summary>
public class T_Grade
{
public T_Grade()
{
T_User = new HashSet<T_User>();
}
/// <summary>
/// id
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 班级名字
/// </summary>
public string GradeName { get; set; }
/// <summary>
/// 班级编号
/// </summary>
public string GradeCode { get; set; } /// <summary>
/// 用户
/// </summary>
public virtual ICollection<T_User> T_User { get; set; }
}

配置DBContext

public class DBEntitys : DbContext
{
public DBEntitys()
: base("DBEntities")
{
this.Configuration.LazyLoadingEnabled = false; //是否开启懒加载 [false/关闭]
}
public DBEntitys(string ConnStr)
: base(ConnStr)
{ }
public virtual DbSet<T_User> T_User { get; set; }
public virtual DbSet<T_Grade> T_Grade { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<T_User>()
.HasRequired<T_Grade>(a => a.T_Grade)
.WithMany(a => a.T_User);
}
}

执行数据库迁移命令以后,生成的表如下:

添加数据进行测试

class Program
{
public static readonly DBEntitys context = new DBEntitys();
static void Main(string[] args)
{
AddData(); //添加数据
var model = context.T_Grade.FirstOrDefault();
foreach (var item in model.T_User)
{
Console.WriteLine("Name:" + item.UserName);
}
Console.Read();
}
/// <summary>
/// 添加数据
/// </summary>
private static void AddData()
{
T_Grade t_Grade = new T_Grade() { GradeName = "一年级", GradeCode = "" };
context.T_Grade.Add(t_Grade);
//一个班级对应两个用户
T_User t_User = new T_User() { UserName = "User1", Account = "admin", Sex = , Password = "", GradeId = t_Grade.Id };
T_User t_User2 = new T_User() { UserName = "User2", Account = "", Sex = , Password = "", GradeId = t_Grade.Id };
context.T_User.Add(t_User);
context.T_User.Add(t_User2);
int row = context.SaveChanges();
Console.Write("数据添加成功");//提示DB添加成功
}
}

Demo下载

2、多对多
在学校里,一个(用户)学生可能有多门课程。同样,一门课程可能有多个(用户)学生选择。

(用户)学生和课程就是多对多的关系。即 ICollection<T_User> t_User 和  ICollection<T_Courses> t_Courses。

public class T_User
{
public T_User()
{
t_Courses = new HashSet<T_Courses>();
} /// <summary>
/// id
/// </summary>
[Required]
[Key]
public int Id { get; set; }
/// <summary>
/// 用户名
/// </summary>
[Required]
[MaxLength()]
public string UserName { get; set; }
/// <summary>
/// 账号
/// </summary>
[Required]
[MaxLength()]
public string Account { get; set; }
/// <summary>
/// Sex
/// </summary>
[Required]
public int Sex { get; set; }
/// <summary>
/// 密码
/// </summary>
[Required]
[MaxLength()]
[Column("Password", TypeName = "varchar")]
public string Password { get; set; }
/// <summary>
/// 地址
/// </summary>
[MaxLength()]
public string Address { get; set; }
/// <summary>
///
/// </summary>
[MaxLength()]
public string Memo { get; set; }
/// <summary>
/// 一个用户有多门课
/// </summary>
public virtual ICollection<T_Courses> t_Courses { get; set; }
}
  /// <summary>
/// 课程类
/// </summary>
public class T_Courses
{
public T_Courses()
{
t_User = new HashSet<T_User>();
}
/// <summary>
/// 主键ID
/// </summary>
[Key]
public int Id { get; set; }
/// <summary>
/// 课程名
/// </summary>
[MaxLength(),Column(TypeName="varchar")]
public string CourseName { get; set; }
/// <summary>
/// 一门课有多个用户
/// </summary>
public virtual ICollection<T_User> t_User { get; set; }
}

执行数据库迁移命令以后生成的数据表如下:

使用配置Fluent API配置多对多关系:

public class DBEntitys : DbContext
{
public DBEntitys()
: base("DBEntities")
{
this.Configuration.LazyLoadingEnabled = true; //是否开启懒加载 [false/关闭]
}
public DBEntitys(string ConnStr)
: base(ConnStr)
{ }
public virtual DbSet<T_User> T_User { get; set; }
public virtual DbSet<T_Courses> T_Courses { get; set; } protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<T_User>()
.HasMany<T_Courses>(a => a.t_Courses)
.WithMany(a => a.t_User)
.Map(a =>
{
a.MapLeftKey("UserId");
a.MapRightKey("CourseId");
a.ToTable("User_Course");
});
}
}

执行测试:

class Program
{
public static readonly DBEntitys context = new DBEntitys();
static void Main(string[] args)
{
//AddData(); //添加数据
var model = context.T_User.FirstOrDefault();
foreach (var item in model.t_Courses)
{
Console.WriteLine("CourseName:" + item.CourseName);
}
Console.Read();
}
/// <summary>
/// 添加数据
/// </summary>
private static void AddData()
{
T_Courses chinese = new T_Courses() { CourseName = "语文" };
T_Courses math = new T_Courses() { CourseName = "数学" };
//一个班级对应两个用户
T_User t_User = new T_User() { UserName = "User1", Account = "admin", Sex = , Password = "" }; t_User.t_Courses.Add(chinese);
t_User.t_Courses.Add(math);
context.T_User.Add(t_User);
int row = context.SaveChanges();
Console.Write("数据添加成功");//提示DB添加成功
}
}

点击下载

Entity Frame Code First 简易教程的更多相关文章

  1. Flow简易教程——安装篇

    .mydoc_h1{ margin: 0 0 1em; } .mydoc_h1_a{ color: #2c3e50; text-decoration: none; font-size: 2em; } ...

  2. 文件上传利器SWFUpload入门简易教程

    凡做过网站开发的都应该知道表单file的确鸡肋. Ajax解决了不刷新页面提交表单,但是却没有解决文件上传不刷新页面,当然也有其它技术让不刷新页面而提交文件,该技术主要是利用隐藏的iFrame, 较A ...

  3. Ant 简易教程

    转载:http://www.cnblogs.com/jingmoxukong/p/4433945.html Ant 简易教程 Apache Ant,是一个将软件编译.测试.部署等步骤联系在一起加以自动 ...

  4. 使用 Entity Framework Code First

    使用 Entity Framework Code First 在家闲着也是闲着,继续写我的[ASP.NET MVC 小牛之路]系列吧.在该系列的上一篇博文中,在显示书本信息列表的时候,我们是在程序代码 ...

  5. Intellj IDEA 简易教程

    Intellj IDEA 简易教程 目录 JDK 安装测试 IDEA 安装测试 调试 单元测试 重构 Git Android 其他 参考资料 Java开发IDE(Integrated Developm ...

  6. Android开发简易教程

    Android开发简易教程 Android 开发因为涉及到代码编辑.UI 布局.打包等工序,有一款好用的IDE非常重要.Google 最早提供了基于 Eclipse 的 ADT 作为开发工具,后来在2 ...

  7. [转]Unity3D Editor 编辑器简易教程

    Star 自定义编辑器简易教程 an introduction to custom editors 原文地址 http://catlikecoding.com/unity/tutorials/star ...

  8. WebGL简易教程(十三):帧缓存对象(离屏渲染)

    目录 1. 概述 2. 示例 2.1. 着色器部分 2.2. 初始化/准备工作 2.2.1. 着色器切换 2.2.2. 帧缓冲区 2.3. 绘制函数 2.3.1. 初始化顶点数组 2.3.2. 传递非 ...

  9. Docker之Ubuntu上使用Docker的简易教程

    Ubuntu上使用Docker的简易教程 原始文档:https://www.yuque.com/lart/linux/fp6cla 说在开头 在天池的比赛中涉及到了docker的使用.经过多番探究,大 ...

随机推荐

  1. GTS-800二次开发基本流程总结

    1.打开控制器 GT_Open 2.启动伺服使能    GT_ClrSts 3.轴规划位置清零 GT_SetPrfPos 4.轴运动模式 GT_PrfTrap 5.轴目标位置 GT_SetPos 6. ...

  2. SharePoint REST API - 同步SharePoint列表项

    博客地址:http://blog.csdn.net/FoxDave 本篇只讲REST服务中的GetListItemChangesSinceToken这个东西.何谓同步呢,你也可以理解为增量变化,即 ...

  3. 容器的注入和container设计的思想——Injection Container 理解

    为什么会出现容器的注入? 容器:顾名思义,装东西的器物. 至于spring中bean,aop,ioc等一些都只是实现的方式:具体容器哪些值得我们借鉴,我个人觉得是封装的思想.将你一个独立的系统功能放到 ...

  4. Django runserver UnicodeDecodeError

    编码问题可以说是我遇到过的python 2.7最大的败笔 今天写django时,很简单的一个项目却报UnicodeDecodeError,而我的代码中一个中文字符都没有出现. 如下: 网上找到的所谓解 ...

  5. webapp 安卓 ios 兼容性问题

    1.ios js中时间不兼容YYYY-MM-DD这种格式的时间,只支持YYYY/MM/DD这种格式 // 在safari中new Date('2018-09-02') // Invalid Daten ...

  6. LINUX系统配置

    LINUX系统配置 Linux 安装jdk方法; Linux Tomcat 安装与配置 Linux redis 安装与配置 (例1) Linux redis安装配置(例2) NGINX 安装 Linu ...

  7. 【转】20-TCP 协议(滑动窗口——基础)

    https://blog.csdn.net/q1007729991/article/details/70142341 相信大家都遇到过这样的场景: 同学 Luffy 给你打电话,让你记下一串手机号码, ...

  8. Linux命令学习之路-文档浏览之less

    使用权限:所有角色 使用方式:less [ options ] filename 作用:文档内容浏览,可向前或者向后浏览文档内容 注意点: 1.less 命令和 more 命令的作用大致相同,less ...

  9. CodeForces - 660D:Number of Parallelograms (问N个点多少个平行四边形)

    pro:给定N个点,问多少个点组成了平行四边形.保证没有三点共线. sol:由于没有三点贡献,所以我们枚举对角线,对角线的中点重合的就是平行四边形.如果没说保证三点不共线就不能这么做,因为有可能4个点 ...

  10. 初窥async,await

    首先是一道今日头条的面试题:(听说是今日头条的并且已经烂大街了) async function async1() { console.log( 'async1 start' ) await async ...