本文来自:http://www.cnblogs.com/xuf22/articles/5513283.html

一、什么是ORM
ORM(Object-relational mapping),中文翻译为对象关系映射,是一种为了解决面向对象与关系数据库存在的互不匹配的现象的技术。
ORM 是将数据存储从域对象自动映射到关系型数据库的工具。
ORM主要包括3个部分:域对象、关系数据库对象、映射关系。ORM使类提供自动化CRUD,使开发人员从数据库API和SQL中解放出来。
简单的说,ORM是通过使用描述对象和数据库之间映射的元数据,将程序中的对象自动持久化到关系数据库中。

为什么用ORM
在程序开发中,数据库保存的表,字段与程序中的实体类之间是没有关联的,在实现持久化时就比较不方便。那么,到底如何实现持久化呢?一种简单的方案是采用硬编码方式,为每一种可能的数据库访问操作提供单独的方法。这种方案存在以下不足: 1.持久化层缺乏弹性。一旦出现业务需求的变更,就必须修改持久化层的接口
2.持久化层同时与域模型与关系数据库模型绑定,不管域模型还是关系数据库模型发生变化,毒药修改持久化曾的相关程序代码,增加了软件的维护难度
ORM提供了实现持久化层的另一种模式,它采用映射元数据来描述对象关系的映射,使得ORM中间件能在任何一个应用的业务逻辑层和数据库层之间充当桥梁 ORM的方法论基于三个核心原则:
简单:以最基本的形式建模数据
传达性:数据库结构被任何人都能理解的语言文档化
精确性:基于数据模型创建正确标准化了的结构
本文以C#编程语言为例,在传统的数据读取操作中,我们以Ado.net的方式对数据库进行CRUD操作,使用的基本都是SQL硬编码,比如有以下数据库查询操作:
String sql = "SELECT ... FROM persons WHERE id = 10";
DbCommand cmd = new DbCommand(connection, sql);
Result res = cmd.Execute();
String name = res[0]["FIRST_NAME"];
使用了ORM映射的C#实现的伪代码:
Person p = repository.GetPerson(10);
String name = p.getFirstName();
上面的示例代码表示我们可以从数据仓库repository中获取到一个实体对象,当然数据仓库中可能包含其他的方法,你也可以定义自己的ORM实现,比如:
Person p = Person.Get(10);
通常,在处理ORM映射和数据仓库时会暴露一些过滤或者查询方法,允许客户端对数据集进行进一步的筛选等操作,比如代码演示从数据库中查询ID=10的用户:
Person p = Person.Get(Person.Properties.Id == 10);
优/缺点
优点
与传统的数据库访问技术相比,ORM有以下优点:
开发效率更高
数据访问更抽象、轻便
支持面向对象封装
缺点
降低程序的执行效率
思维固定化
从系统结构上来看,采用ORM的系统一般都是多层系统,系统的层次多了,效率就会降低。ORM是一种完全的面向对象的做法,而面向对象的做法也会对性能产生一定的影响。 总结
作为一名编程人员,在ORM使用的观念上会有不同,具体取舍需根据具体的项目和场景

二、什么是Entity Framework

微软官方提供的ORM工具,ORM让开发人员节省数据库访问的代码时间,将更多的时间放到业务逻辑层代码上。EF提供变更跟踪、唯一性约束、惰性加载、查询事物等。开发人员使用Linq语言,对数据库操作如同操作Object对象一样省事。

EF有三种使用场景,1. 从数据库生成Class,2.由实体类生成数据库表结构,3.  通过数据库可视化设计器设计数据库,同时生成实体类。

三、Entity Framework 架构

EDM (实体数据模型):EDM包括三个模型,概念模型、 映射和存储模型。

概念模型 ︰ 概念模型包含模型类和它们之间的关系。独立于数据库表的设计。

存储模型 ︰ 存储模型是数据库设计模型,包括表、 视图、 存储的过程和他们的关系和键。

映射 ︰ 映射包含有关如何将概念模型映射到存储模型的信息。

LINQ to Entities ︰ LINQ to Entities 是一种用于编写针对对象模型的查询的查询语言。它返回在概念模型中定义的实体。

Entity SQL: Entity SQL 是另一种炉类似于L2E的言语,但相给L2E要复杂的多,所以开发人员不得不单独学习它。

Object Services(对象服务):是数据库的访问入口,负责数据具体化,从客户端实体数据到数据库记录以及从数据库记录和实体数据的转换。

Entity Client Data Provider:主要职责是将L2E或Entity Sql转换成数据库可以识别的Sql查询语句,它使用Ado.net通信向数据库发送数据可获取数据。

ADO.Net Data Provider:使用标准的Ado.net与数据库通信

四、Entity Framework运行环境

EF5由两部分组成,EF api和.net framework 4.0/4.5,而EF6是独立的EntityFramework.dll,不依赖.net Framework。使用NuGet即可安装EF。

    

五、创建实体数据模型

使用向导创建实体类,或键添加,傻瓜式的~

添加完成之后,.config文件中会添加以下配置

<?xmlversion="1.0"?><configuration><configSections><!-- For more information on Entity Framework configuration, visit http://go.microsoft.com/fwlink/?LinkID=237468 --><sectionname="entityFramework"type="System.Data.Entity.Internal.ConfigFile.EntityFrameworkSection, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"requirePermission="false"/></configSections><startup><supportedRuntimeversion="v4.0"sku=".NETFramework,Version=v4.5"/></startup><entityFramework><defaultConnectionFactorytype="System.Data.Entity.Infrastructure.SqlConnectionFactory, EntityFramework"/><providers><providerinvariantName="System.Data.SqlClient"type="System.Data.Entity.SqlServer.SqlProviderServices, EntityFramework.SqlServer"/></providers></entityFramework><connectionStrings><addname="SchoolDBEntities"connectionString="metadata=res://*/SchoolDB.csdl|res://*/SchoolDB.ssdl|res://*/SchoolDB.msl;provider=System.Data.SqlClient;provider connection string=&quot;data source=.\sqlexpress;initial catalog=SchoolDB;integrated security=True;multipleactiveresultsets=True;application name=EntityFramework&quot;"providerName="System.Data.EntityClient"/></connectionStrings></configuration>

Context & Entity 类:

每个Entity Data Model 生成一个context类,类数据库每个表生成一个entity类。如在School.edmx中包含的两个重要的文件{EDM Name}.context.tt和{EDM Name}.tt:

School.Context.tt:T4模板用于生成的context类,可以从目录结构中看到School.Context.tt下包含一个School.Context.cs文件。

School.tt:用于生成表映射的实体类。Entity类是POCO类。如Student生成

publicpartialclassStudent

{

public Student()

{

this.Courses = new HashSet<Course>();

}

publicint StudentID { get; set; }

publicstring StudentName { get; set; }

publicNullable<int> StandardId { get; set; }

publicbyte[] RowVersion { get; set; }

publicvirtualStandard Standard { get; set; }

publicvirtualStudentAddress StudentAddress { get; set; }

publicvirtualICollection<Course> Courses { get; set; }

}

六、模板浏览器

以SchoolDB为例,切换到Model View视图下,看到类图结构:

七、DBContext

第四节中提到EDM生成SchoolDBEntities类,该类从System.Data.Entity.DbContext类继承。EntityFramework4.1中Context类从ObjectContext类继承。DbContext类与ObjectContext类似,它对ObjcetContext类进行包装更利于开发的三种模式:CodeFirst、Model First、Database First.

DbContext是EntityFramework很重要的部分,连接域模型与数据库的桥梁,是与数据库通信的主要类。

DbContext主要负责以下活动:

EntitySet::DbContext包含了所有映射到表的entities

Querying:将Linq-To-Entities转译为Sql并发送到数据库

Change Tracking:从数据库获取entities后保留并跟踪实体数据变化

Persisting Data:根据entity状态执行Insert、update、delete命令

Caching:DbContext的默认第一级缓存,在上下文中的生命周期中存储entity

Manage Relationship:DbContext在DbFirst模式中使用CSDL、MSL、SSDL管理对象关系,Code first中使用fluent api 管理关系

Object Materialization:DbContext将物理表转成entity实例对象

DEMO

DbContext实例化:

using (var ctx = newSchoolDBEntities())
{
//Can perform CRUD operation using ctx here..
}

将DbContext转为ObjectContext

using (var ctx = newSchoolDBEntities())
{
var objectContext = (ctx as System.Data.Entity.Infrastructure.IObjectContextAdapter).ObjectContext;
//use objectContext here..
}

八、Entity Framework中的Entity类型

POCO Entity (Plain Old CLR Object):

不依赖于任何Framework的类的类(also known as persistence-ignorant objects),为Entity Data Model生成CRUD命令服务。

public class Student
{

public Student()

{

this.Courses = new List<Course>();

}

public int StudentID { get; set; }

public string StudentName { get; set; }

public Nullable<int> StandardId { get; set; }

public Standard Standard { get; set; }

public StudentAddress StudentAddress { get; set; }

public IList<Course> Courses { get; set; }

}

Dynamic Proxy (POCO Proxy):

Dynamic Proxy是运行时POCO类的代理类,类似POCO类的包装。Dynamic Proxy允许延迟加载(Lazy loading),自动跟踪更改。POCO Entity必需满足以下几点才能转为POCO Proxy:

1. 必需声明为public 类

2. 不可以是sealed类

3. 不可以是抽象类

4. 导航属性必需是public,vitual(Entity包含两种属性,标量属性Scalar properties:Entity本身的字段值,Navigation properties:其它entity的引用如班级-学生)

5. 集合属性必需是 ICollection<T>

6. ProxyCreationEnabled 选项必需是true

public class Student

{

public Student()

{

this.Courses = new HashSet<Course>();

}

public int StudentID { get; set; }

public string StudentName { get; set; }

public Nullable<int> StandardId { get; set; }

public virtual Standard Standard { get; set; }

public virtual StudentAddress StudentAddress { get; set; }

public virtual ICollection<Course> Courses { get; set; }

}

九、Entity Relationships:

十、 Entity Lifecycle

在我们做CRUD操作时,要先了解EntityFramework如何管理实体状态。每个实体的生命周期内都会在DbContext上下文中保存一个状态,分别是

Added Deleted Modified Unchanged Detached

十一、Code First、DBFirst、Model First

CodeFirst 领域设计时先定义实体类,用实体类生成数据库

DbFirst 从数据库生成实体类

Model First 使用Visual Studio实体设计器,设计ER,同时生成Entity类和DB

十二、使用查询

三种查询方式1) LINQ to Entities, 2) Entity SQL, and 3) Native SQL

LINQ to Entities:

LINQ Method syntax:

//Querying with LINQ to Entities

using (var context = newSchoolDBEntities())

{

var L2EQuery = context.Students.where(s => s.StudentName == "Bill");

var student = L2EQuery.FirstOrDefault<Student>();

}

LINQ Query syntax:

using (var context = new SchoolDBEntities())

{

var L2EQuery = from st in context.Students

where st.StudentName == "Bill"select st;

var student = L2EQuery.FirstOrDefault<Student>();

}

Entity SQL:

//Querying with Object Services and Entity SQL

string sqlString = "SELECT VALUE st FROM SchoolDBEntities.Students " +

"AS st WHERE st.StudentName == 'Bill'";

var objctx = (ctx as IObjectContextAdapter).ObjectContext;

ObjectQuery<Student> student = objctx.CreateQuery<Student>(sqlString);

Student newStudent = student.First<Student>();

//使用EntityDataReader

using (var con = newEntityConnection("name=SchoolDBEntities"))

{

con.Open();

EntityCommand cmd = con.CreateCommand();

cmd.CommandText = "SELECT VALUE st FROM SchoolDBEntities.Students as st where st.StudentName='Bill'";

Dictionary<int, string> dict = newDictionary<int, string>();

using (EntityDataReader rdr = cmd.ExecuteReader(CommandBehavior.SequentialAccess | CommandBehavior.CloseConnection))

{

while (rdr.Read())

{

int a = rdr.GetInt32(0);

var b = rdr.GetString(1);

dict.Add(a, b);

}

}

}

Native SQL:

using (var ctx = newSchoolDBEntities())

{

var studentName = ctx.Students.SqlQuery("Select studentid, studentname, standardId from Student where studentname='Bill'").FirstOrDefault<Student>();

}

十三、跟踪变更与持久化场景

在连接状态下持久化与脱机状态下持久化

连机状态下持久化,在同一个DbContext中不需要销毁Entity,直接写入数据库

脱机状态持久化指读取和保存Entity在两个不同的DbContext中,Context2不知道Entity的更新状态,所以必需通知Context2当前的Entity做了何种更新。

Context只在DbSet上跟踪添加和删除

正确的添加和删除

using (var context = new SchoolDBEntities())

{

var studentList = context.Students.ToList<Student>();

//Perform create operation

context.Students.Add(newStudent() { StudentName = "New Student" });

//Perform Update operationStudent studentToUpdate = studentList.Where(s => s.StudentName == "student1").FirstOrDefault<Student>();

studentToUpdate.StudentName = "Edited student1";

//Perform delete operation

context.Students.Remove(studentList.ElementAt<Student>(0));

//Execute Inser, Update & Delete queries in the database

context.SaveChanges();

}

以下代码在List中添加和删除不起作用,只有更生有效

using (var context = new SchoolDBEntities())

{

var studentList = context.Students.ToList<Student>();

//Add student in list

studentList.Add(new Student() { StudentName = "New Student" });

//Perform update operationStudent studentToUpdate = studentList.Where(s => s.StudentName == "Student1").FirstOrDefault<Student>();

studentToUpdate.StudentName = "Edited student1";

//Delete student from listif (studentList.Count > 0)

studentList.Remove(studentList.ElementAt<Student>(0));

//SaveChanges will only do update operation not add and delete

context.SaveChanges();

}

脱机实体

脱机实体管理要先附加到Context

//disconnected entity graphStudent disconnectedStudent = newStudent() { StudentName = "New Student" };

disconnectedStudent.StudentAddress = newStudentAddress() { Address1 = "Address", City = "City1" };

using (var ctx = newSchoolDBEntities())

{

//attach disconnected Student entity graph to new context instance - ctx

ctx.Students.Attach(disconnectedStudent);

// get DbEntityEntry instance to check the EntityState of specified entity

var studentEntry = ctx.Entry(disconnectedStudent);

var addressEntry = ctx.Entry(disconnectedStudent.StudentAddress);

Console.WriteLine("Student EntityState: {0}",studentEntry.State);

Console.WriteLine("StudentAddress EntityState: {0}",addressEntry.State);

}

添加多个关系实体时与添加单个实体一样,更新关系实体时需要跟踪每个实体的状态。

十四、 Entity Framework并发处理

添加RowVersion,类型为TimeStamp字段,在EDM中X修改并发属性为Fixed。EF更新实体时会先检查RowVersion,如果发现RowVersion不一致,则抛出DbUpdateConcurrencyException异常

十五、 贪婪加载、惰性加载与定向加载

贪婪加载:使用Include(),自动加载关联实体

using (var context = new SchoolDBEntities())

{

var res = (from s in context.Students.Include("Standard")

where s.StudentName == "Student1"

select s).FirstOrDefault<Student>();

}

执行Sql

SELECTTOP (1)

[Extent1].[StudentID] AS [StudentID],

[Extent1].[StudentName] AS [StudentName],

[Extent2].[StandardId] AS [StandardId],

[Extent2].[StandardName] AS [StandardName],

[Extent2].[Description] AS [Description]

FROM [dbo].[Student] AS [Extent1]

LEFTOUTERJOIN [dbo].[Standard] AS [Extent2] ON [Extent1].[StandardId] = [Extent2].[StandardId]

WHERE'Student1' = [Extent1].[StudentName]

惰性加载:延迟加载对象关联的实体,用到时再加载,EF默认为LazyLoading

using (var ctx = newSchoolDBEntities())

{

//Loading students onlyIList<Student> studList = ctx.Students.ToList<Student>();

Student std = studList[0];

//Loads Student address for particular Student only (seperate SQL query)

StudentAddress add = std.StudentAddress;

}

定向加载:Reference()和Collection() 方法

using (var context = new SchoolDBEntities())

{

//Loading students only

IList<Student> studList = context.Students.ToList<Student>();

Student std = studList.Where(s => s.StudentID == 1).FirstOrDefault<Student>();

//Loads Standard for particular Student only (seperate SQL query)

context.Entry(std).Reference(s => s.Standard).Load();

//Loads Courses for particular Student only (seperate SQL query)

context.Entry(std).Collection(s => s.Courses).Load();

}

十六:执行SQL

返回实体

using (var ctx = newSchoolDBEntities())

{

//列名必需要Entity属性匹配

var studentList = ctx.Students.SqlQuery("Select * from Student").ToList<Student>();

}

返回非实体类型

using (var ctx = newSchoolDBEntities())

{

//Get student name of string typestring studentName = ctx.Database.SqlQuery<string>("Select studentname

from Student where studentid=1").FirstOrDefault<string>();

}

执行SQL命令

using (var ctx = new SchoolDBEntities())

{

//Update commandint noOfRowUpdated = ctx.Database.ExecuteSqlCommand("Update student

set studentname ='changed student by command' where studentid=1");

//Insert commandint noOfRowInserted = ctx.Database.ExecuteSqlCommand("insert into student(studentname)

values('New Student')");

//Delete commandint noOfRowDeleted = ctx.Database.ExecuteSqlCommand("delete from student

where studentid=1");

}

C#:ORM--实体框架EF(entity framework)(1)的更多相关文章

  1. 实体框架(Entity Framework)简介

    实体框架(Entity Framework)简介 简称EF,与ADO.NET关系 ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R ...

  2. 实体框架(Entity Framework)

    实体框架(Entity Framework) 实体框架(Entity Framework)简介 ADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对 ...

  3. 【转】在使用实体框架(Entity Framework)的应用中加入审计信息(Audit trail)跟踪数据的变动

    在一些比较重要的业务系统中,通常会要求系统跟踪数据记录的变动情况.系统要记录什么时间,什么人,对那些信息进行了变动. 比较简单的实现方式是在每个表中加入两个字段CreatedBy和CreatedAt, ...

  4. 在使用实体框架(Entity Framework)的应用中加入审计信息(Audit trail)跟踪数据的变动

    在一些比较重要的业务系统中,通常会要求系统跟踪数据记录的变动情况.系统要记录什么时间,什么人,对那些信息进行了变动. 比较简单的实现方式是在每个表中加入两个字段CreatedBy和CreatedAt, ...

  5. [转载]灵动思绪EF(Entity FrameWork)

    很久之前就想写这篇文章了,但是由于种种原因,没有将自己学习的EF知识整理成一片文章.今天我就用CodeFirst和ModelFirst两种方式的简单案例将自己学习的EF知识做个总结. 在讲解EF之前, ...

  6. EF(Entity Framework)多对多关系下用LINQ实现"NOT IN"查询

    这是今天在实际开发中遇到的一个问题,需求是查询未分类的博文列表(未加入任何分类的博文),之前是通过存储过程实现的,今天用EF实现了,在这篇博文中记录一下. 博文的实体类BlogPost是这样定义的: ...

  7. EF(Entity Framework)通用DBHelper通用类,增删改查以及列表

    其中 通用类名:DBhelper 实体类:UserInfo 1 //新增 2 DBHelper<UserInfo> dbhelper = new DBHelper<UserInfo& ...

  8. Entity Framework(实体框架 EF)

    什么是Entity Framework呢(下面简称EF)? EF(实体框架)是ADO.NET中的一组支持开发面向数据的软件应用程序的技术,是微软的一个ORM框架.ORM(对象关系映射框架):指的是面向 ...

  9. ORM框架 之 Entity Framework

    Entity Framework 1.ADO.NET Entity Framework是以ADO.NET为基础所发展出来的对象关系对应(O/R Mapping)解决方案,早起被称为ObjectSpac ...

  10. 实体框架(Entity Frmaework)简介

    l简称EF  NH l与Asp.Net MVC关系与ADO.NET关系 lADO.NET Entity Framework 是微软以 ADO.NET 为基础所发展出来的对象关系对应 (O/R Mapp ...

随机推荐

  1. 双缓冲队列解决WPF界面卡死

    工作中的项目,CS客户端会通过MQ接收前端设备发送的信息,之前测试的时候,由于测试的数据不大,没有进行压力测试,软件可以正常工作,随着项目现场设备数量的增加,CS客户端从MQ中订阅的数据量不断增加,最 ...

  2. xt

    using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; usin ...

  3. Socket编程入门

      socket基本知识 网络上的两个程序通过一个双向的通信连接实现数据的交换,这个连接的一端称为一个socket. 建立网络通信连接至少要一对端口号(socket).socket本质是编程接口(AP ...

  4. 4、Orcal数据库dmp文件导入

    1.CMD命令导入备份数据库dmp文件: 以上一篇博客提到的gdnh用户,我们需要在cmd窗口执行如下命令: imp gdnh/admin123@orcl file=E:/createTable.dm ...

  5. 经典贪心算法(哈夫曼算法,Dijstra单源最短路径算法,最小费用最大流)

    哈夫曼编码与哈夫曼算法 哈弗曼编码的目的是,如何用更短的bit来编码数据. 通过变长编码压缩编码长度.我们知道普通的编码都是定长的,比如常用的ASCII编码,每个字符都是8个bit.但在很多情况下,数 ...

  6. Retrofit源码解析(下)

    接着上一章继续分析上一章主要简单说了一下基本使用和注解,这一章,我们主要看源码,废话不多说了,直接上.先上一张图 从网络上拿来的 前面一章说了一下Retrofit的简单使用https://www.cn ...

  7. 找到SVN版本机上项目的地址

    在你的项目文件上右击:点击Copy URL to Clipboard(复制URL到剪切板)

  8. php 中的查找算法 和 排序方法(多字段排序)

    一.查找算法 1.顺序查找(一个一个查,效率低,不用多说) 2.二分查找 /* php 二分查找 在$a数组里查找$x的位置 $a必须是一个以升序排序后的数组 */ function binsearc ...

  9. 目标检测算法—YOLO-V1

    为什么会叫YOLO呢? YOLO:you only look once.只需要看一眼,就可以检测识别出目标,主要是突出这个算法 快 的特点.(原文:Yolo系列之前的文章:主要是rcnn系列的,他们的 ...

  10. Openerp负载平衡

    来自OpenERP 7.0 带来了许多新特性,架构上也有许多改进.其中可配置 worker 参数,可使 OpenERP 运行在多进程模式,突破GIL的限制,有效利用了现代多核CPU的性能.但默认情况下 ...