积跬步,为的是千里之遥!
一、ADO.NET 的存储方式
之前我们都是通过 ADO.NET 提供的类,把我们要执行的SQL语句传递到底层数据库引擎,来进行解析执行,然后获取返回结果。
这种开发方式具有非常大的弹性,但相对也存在一定的风险。
从SQL语句的处理到数据类型的转换都可能发生错误,特别是随着系统规模的逐渐增长,这些错误造成的问题将越发严重。
二、Entity Framework 的存储方式
Entity Framework 通过实体数据模型映射到底层的数据结构,开发人员只需编写C#程序代码来处理实体数据对象,
从而降低了因SQL不规范而导致的程序错误和安全性问题。
由于数据对象本身具有类型,因此在程序开发的过程中避免了因类型转换可能导致错误的程序代码。
三、Entity Framework 项目实现
1. 先来看看,“来自数据库的 EF 设计器”
首先,得准备好个数据库文件 StudentInfo.mdf,这个数据库里就一个名为 Student 的表:
然后,创建C#控制台应用程序 MyEFProject, 并在项目中添加新建项 “ADO.NET 实体数据模型”。
ok,紧接着会弹出 添加新建项 窗口,选择 “ADO.NET 实体数据模型”,并将其名称更改为 “StudentInfoModel” 。
接着会这么着:
使用 EF 之后,如何对表对象进行操作呢?下图:
这样就可以轻轻松松的进行数据处理了!
四、实体类型和 .edmx 文件
实体数据类型是一种XML格式的纯文本文件,以 .edmx 为扩展名。
.edmx 文件内容包括:存储模型、概念模型、以及两种模型之间的相关设置。
Visual Studio 提供了 实体数据模型设计器(ADO.NET Entity Data Model Desiger),它是一款可视化图形工具。
双击项目中的 .edmx 文件,就可以打开这个工具,界面如下:
如果想查看该文件的原始文件内容,可以使用 XML编辑器 方式进行打开 .edmx 文件。
打开之后就是一个比较传统的(traditional) XML文件:
实体模型包含三部分:
- 存储模型(SSDL,Store Schema Definition Language,存储结构定义语言)
- 概念模型(CSDL,Conceptual Schema Definition Language,概念模式定义语言)
- 映射 (MSL,Mapping Specification Language,映射规范语言)
1、存储模型:
概念模型是用来存储原始数据库的结构信息,其结构中包含描述对象内容的元素:EntityContainer 和 EntityType 。
a、EntityContainer 元素: 表示这个区域是一个实体容器,对应特定的数据源。
<EntityContainer Name="StudentInfoModelStoreContainer"> <EntitySet Name="Student" EntityType="Self.Student" Schema="dbo" store:Type="Tables" /> </EntityContainer>
比如这里对应的是要操作的数据库 StudentInfo.mdf,使用LINQ相关技术搜索其内容时,一个对应的 StudentInfoEntities 类型对象被返回,
应用程序可通过此对象与数据库进行互动。
其中的 EntitySet 元素描述了实体容器中所包含的数据对象内容。
b、EntityType 元素: 表示对应相关数据内容中的实体类型 Student (如同数据表 Student 中的信息)。
实体类型元素以 <EntityType Name="Student"> 表示,表示数据模型映射的 Student 类。
而节点 <Key><PropertyRef Name="Id" /></Key> 表示数据模型的主键对应属性 (如同数据表中的主键)。
接下来一连串的属性配置,分别对应 Student 类中的各个属性的特性内容:属性名称(Name)、属性类型(Type)以及是否为空(Nullable)等等。
<Property Name="Id" Type="int" StoreGeneratedPattern="Identity" Nullable="false" />
Property 元素的特性在程序执行过程中,会进一步映射到实体数据模型连接的底层数据库,
在 EF 中被称为facet,根据不同的数据类型,均有其特定的facet可供设置,它们描述除了数据大小之外的其他特性的额外信息。
2、存储模型:
概念模型定义实体数据模型与类结构,然后通过存储模型映射到底层数据源结构。
可以看出 其中内容与 概念模型 相似,不过要注意的是,它的实体类型与属性均是来自于低层数据库的真实名称。
3、映射:
这个模块负责支持存储模型与概念模型两个区块的内容映射。这么一来,实体数据属性才能映射到底层的数据源。
可以看到,映射模块将 Student 实体的属性名称(Name)逐一映射到底层数据库的 Student 数据表的字段名(ColumnName)。
我们还可以通过 实体设计器 来查看它们的映射关系:
五、实体数据模型与类文件
1、DbContext 和 DbSet
除了数据模型的内容外,我们必须要了解的两个类:DbContext 和 DbSet 。
DbContext 类:程序通过 DbContext 的对象实例来建立与数据库的连接,并支持数据库的查询与更新等相关操作。
DbSet 类:这个类主要起到映射作用,映射到特定的数据表结构,表示映射的数据表其实体数据内容的集合。
每一个实体数据模型都会建立 DbContext 类以供程序进行数据连接,并根据数据库中的表结构逐一创建对应的DbSet类,
程序则进一步通过类的调用,在EF的环境下执行各种数据库操作。
来看下 StudentInfoModel.Context.cs 这个文件:
StudentInfoEntities 继承了 DbContext 类,而 Student 属性 返回的是Student 类的 DbSet 对象,它映射的是 StudentInfoEntities 连接数据库中的 Student 表,表示 Student 的数据集合。
在 StudentInfoModel.tt 4T 模板的节点下,可以找到定义的 Student 类。
其中的属性逐一映射到 Student 数据表结构字段。
有了DbContext 和 DbSet 这两个重要的类以后,我们就可以通过以下代码来建立数据库连接,并获取到Student表中的数据了:
//StudentInfoEntities 继承了 DbContext 类,因此 stuInfo 是一个 DbContext 对象,它与数据库完成了连接操作; //通过调用 stuInfo 的 Student 属性,即可获取到数据库 Student 表中的数据内容,并将其封装成 DbSet<Student> 对象返回给 stus。 StudentInfoEntities stuInfo = new StudentInfoEntities(); DbSet<Student> stus = stuInfo.Student; //DbSet 是一组数据集,为了方便遍历其数据,可以通过 ToList 方法将其转换成 List 类型。 List<Student> list = stuInfo.Student.ToList(); //也可以通过 LINQ 来进行转换 IEnumerable<Student> students = stuInfo.Student.Select(x => x);
Student 表中的每一条数据对应的封装成一个 Student 对象,再通过 Student 对象的属性获取相应的数据内容。