EntityFramework学习笔记4-实体数据模型及增、删、改操作
下面我们通过建立一个简单的例子来学习EF框架,直接进入主题吧:
一 、创建实体数据模型
1. 创建一个控制台应用程序,起名为EFDemo
2. 创建一个实体模型
在EFDemo项目上面右击选择添加—新建项—在已安装的选项中选择数据—ADO.NET实体对象模型,命名为EFStudy
3. 与数据库连接
第2步执行完毕会弹出向导,选择“从数据库生成”,点击“新建连接…”按钮,选择sql server,下略,测试连接成功后,确定返回,注意下方的App.Config会自动生成一个数据库名+Entities的名字,此名字会成为上下文的类名,建议修改为***+Context,比如PopContext,然后点击下一步
4. 指定相应的库表、视图和存储过程生成实体
勾选对应的库表、视图和存储过程生成实体,点击完成即可。
注:可事先在sql server数据库中使用以下语句建一张简单的表
CREATE TABLE [dbo].[SysDept](
[ID] [varchar](16) primary key,
[Name] [varchar](64) NOT NULL
)
GO
以上步骤操作完毕后,在项目中新增文件EFStudy.edmx,并以图形化方式显示SysDept类
二、增删改操作
1.新增
因为前面创建的是控制台应用程序,且为了清晰,只引入了一张表,代码也从简,直接在Program.cs里面写
static void Main(string[] args) { //新增 InsertDept(); } private static void InsertDept() { //数据库表SysDept已经被EF映射为了SysDept类 //此处可直接使用来定义对象 SysDept sysDept = new SysDept(); //为对象设置属性 sysDept.ID = "1"; sysDept.Name = "烟台**公司"; //EF已经创建了上下文对象,类名为创建实体类型阶段指定的PopContext PopContext context = new PopContext(); //将sysDept对象加入到上下文对象,三种方式 //方式一(推荐) context.SysDept.AddObject(sysDept); //方式二 //context.AddToSysDept(sysDept); //方式三 //context.AddObject("SysDept", sysDept); //以上操作后数据变更在内存中,执行以下操作后保存到数据库 int i=context.SaveChanges(); Console.WriteLine("影响行数:"+i); }
如上所示,将实体对象添加到上下文对象有三种方式,推荐第一种,符合习惯和自然,第二种在库表比较多的情况下,难以查找,第三种第一个参数采用字符串,易拼写错误且繁琐
使用sql server 自带的SQL Server Profiler(开始—》SQL Server 2008-》性能工具,若找不到,说明你安装的sql server版本是express,开发版和企业版都有该工具),可查看数据库执行的每条sql,即可以观察上述程序执行时,EF将程序中对对象的操作转换为具体的sql语句,对于初期阶段理解学习以及后期的多表关联下性能调优大有益处。
2.删除
要删除某条记录,就要先找到该条记录,有两种方式,一是定义一个新对象,通过Context的Attach方法将该对象加入管理,如下面代码所示,二是在上下文对象中查找,代码在修改例子中体现
private static void DeleteDept() { //先定义一个新对象并设置主键属性 SysDept sysDept = new SysDept(); sysDept.ID = "1"; //将此对象附加到上下文对象 PopContext context = new PopContext(); context.SysDept.Attach(sysDept); //移除对象,两种方法 //方法一,推荐 context.SysDept.DeleteObject(sysDept); //context.DeleteObject(sysDept);//方法二 //以上操作后数据变更在内存中,执行以下操作后保存到数据库 int i = context.SaveChanges(); Console.WriteLine("影响行数:" + i); }
网上查找资料,发现好多是以下两种方式,可能在早期版本支持,在EF5.0中已过时,context既无Entry方法,也无Remove方法,sysDept.EntityState属性只读,不可设置
1.context.Entry(sysDept).State = EntityState.Deleted;//EntityState枚举值需using System.Data;
2.context.SysDept.Remove(sysDept)
3.修改
要修改某条记录,就要先找到该条记录
private static void UpdateDept() { //找到要修改的记录,查找参数为lamda表达式,看不懂的可补习相关知识 PopContext context = new PopContext(); SysDept sysDept = context.SysDept.FirstOrDefault(dept => dept.ID == "1"); //修改属性 sysDept.Name = "青岛**公司"; //以上操作后数据变更在内存中,执行以下操作后保存到数据库 int i = context.SaveChanges(); Console.WriteLine("影响行数:" + i); }
这里体现了上文所说查找记录的第二种方式,事实上,采用这种方式先找到对象,再对对象进行删除或者修改操作更符合常理。
同删除类似,EF5.0中已没有context.Entry(sysDept).State = EntityState.Modified的写法
4.事务处理
上面说了增、删、改,程序中常用到的还有事务处理,与do.net处理类似
private static void Transaction() { PopContext context = new PopContext(); IDbTransaction trans = null; try { //打开连接 context.Connection.Open(); //开始事务 trans=context.Connection.BeginTransaction(); //执行操作 //修改一记录 SysDept sysDept = context.SysDept.FirstOrDefault(dept => dept.ID == "1"); sysDept.Name = "临沂****公司"; //新增一记录 sysDept = new SysDept { ID = "2", Name = "菏泽***公司" }; context.SysDept.AddObject(sysDept); //保存到数据库 int i=context.SaveChanges(); //提交事务 trans.Commit(); Console.WriteLine("已成功执行,影响行数:"+i); } catch (Exception ex) { trans.Rollback(); Console.WriteLine("发生异常,已回滚" + ex.Message); } finally { context.Connection.Close(); } }
上述过程第一次执行正常提交,把sysDept.Name = "临沂****公司";中“临沂”改为“日照”,再执行一次,则会因为重复插入主键异常退出,查看数据库会发现,不仅新数据没插进去,而且在插入数据之前修改的数据也没有保存到数据库,从而说明实现了回滚功能。
注意:此处回滚仅对数据库有效,内存中PopContext对象中的"临沂****公司"已经被更改了,回滚不会将内存中的数据恢复到事务前状态。
三、小结
从本节内容就能看出ORM的优点了,在程序中一方面不需要再写与数据库对应的的INSERT/DELETE/UPDATE的SQL语句,特别是在表字段比较多的情况下,写一个比较长的Insert语句,很容易发生错位、缺失问题,另一方面可以直接实例化对象,获取或者设置属性值时,智能提示很友好也很便利。