这里我接上讲Entity Framework入门。从网上下载Northwind数据库,新建一个控制台程序,然后重新添加一个ado.net实体数据模型。
EF中操作数据库的"网关"(操作上下文)
DBContext封装 .NET Framework 和数据库之间的连接。此类用作“创建”、“读取”、“更新”和“删除”操作的网关。
DBContext 类为主类,用于与作为对象(这些对象为 EDM 中定义的实体类型的实例)的数据进行交互。
DBContext 类的实例封装以下内容:
- 到数据库的连接,以 EntityConnection 对象的形式封装。
- 描述该模型的元数据,以 MetadataWorkspace 对象的形式封装
- 用于管理缓存中持久保存的对象的 ObjectStateManager 对象
一、新增
#region 新增 1.0 static int Add() { Customers _Customers = new Customers {CustomerID="zhang",Address="洛阳西街",City="洛阳",Phone="1314520",
CompanyName="微软",ContactName="李四" }; //方法一 //db.Customers.Add(_Customers); //方法二 DbEntityEntryentry = db.Entry (_Customers); entry.State = System.Data.Entity.EntityState.Added; return db.SaveChanges(); } #endregion
二、简单查询 延时加载
为了查看延时加载,要使用SqlProfiler跟踪sql语句
EF生成sql语句发送给数据库执行,我们可以使用sqlserver的跟踪监测工具查看。(可监测sql语句、CPU占用、执行时间等)
【延时加载】 看成两种:
1、 EF本身查询方法 返回的都是 IQueryable接口,此时并未查询数据库;只有当调用接口方法 获取 数据时,才会查询数据库
2、 【延时加载】,本质原因之一:当前可能通过多个SQO方法 来组合 查询条件,那么每个方法 都只是添加一个查询条件而已,无法确定本次查询条件 是否 已经添加结束 所以,没有办法在每个SQO方法的时候确定SQL语句是什么,只能返回一个 包含了所有添加的条件的 DBQuery 对象, 当使用这个 DBQuery对象 的时候,才根据所有条件 生成 sql语句,查询数据库
#region 2.1 简单查询 延迟加载 -void QueryDelay_01() static void QueryDelay_01() { DbQuerydbQuery = db.Customers.Where(u => u.ContactName == "张学友").OrderBy(u => u.ContactName).Take(2)
as System.Data.Entity.Infrastructure.DbQuery; //获得 延迟查询对象后,调用对象的 获取第一个数据方法,此时,【就会根据之前的条件】,生成sql语句,查询数据库了~~! Customers usr01 = dbQuery.FirstOrDefault();// ToList()...... Console.WriteLine(usr01.ContactName); } //2.1.2【延迟加载】- 针对于 外键实体 的延迟(按需加载)! // 本质原因之二:对于外键属性而言,EF会在用到这个外键属性的时候才去查询 对应的 表。 static void QueryDelay_02() { IQueryable _Orders = db.Orders.Where(a => a.CustomerID == "TOMSP");//真实返回的 DbQuery 对象,以接口方式返回 //a.此时只查询了 地址表 Orders order = _Orders.FirstOrDefault(); //b.当访问 地址对象 里的 外键实体时,EF会查询 地址对应 的用户表;查询到之后,将数据 装入 这个外键实体 Console.WriteLine(order.Customers.ContactName); //c.【延迟加载】按需加载 的缺点:每次调用外键实体时,都会去查询数据库(EF有小优化:相同的外键实体只查一次) IQueryable orderList = db.Orders; foreach (Orders o in orderList) { Console.WriteLine(o.OrderID + ":ContactName=" + o.Customers.ContactName); } } #endregion
#region 2.2 根据条件 排序 和查询 + ListGetListBy /// /// 2.2 根据条件 排序 和查询 /// /// 排序字段类型 /// 查询条件 lambda表达式 /// 排序条件 lambda表达式 /// public List GetListBy (Expression bool>> whereLambda, Expression > orderLambda) { return db.Customers.Where(whereLambda).OrderBy(orderLambda).ToList(); } #endregion #region 2.3 分页查询 + List GetPagedList /// /// 2.3 分页查询 + List GetPagedList /// /// 页码 /// 页容量 /// 条件 lambda表达式 /// 排序 lambda表达式 /// public List GetPagedList (int pageIndex, int pageSize, Expression bool>> whereLambda,
Expression> orderBy) { // 分页 一定注意: Skip 之前一定要 OrderBy return db.Customers.Where(whereLambda).OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); } #endregion
三、修改
#region 3.0 官方推荐的 修改方式(先查询,再修改) ////// 3.0 官方推荐的 修改方式(先查询,再修改) /// static void Edit() { //1.查询出一个 要修改的对象 -- 注意:此时返回的 是 一个 Customers类的 代理类对象(包装类对象) Customers _Customers = db.Customers.Where(u => u.CustomerID == "zhang").FirstOrDefault(); Console.WriteLine("修改前:" + _Customers.ContactName); //2.修改内容 -- 注意:此时其实操作的 是 代理类对象 的属性,这些属性,会将值设置给内部的 Customers对象对应的属性,同时标记此属性为已修改状态 _Customers.ContactName = "刘德华"; //3.重新保存到数据库 -- 注意:此时 ef上下文,会检查容器内部 所有的对象,找到标记为修改的对象,然后找到标记为修改的对象属性,生成对应的update语句执行! db.SaveChanges(); Console.WriteLine("修改成功:"); Console.WriteLine(_Customers.ContactName); } #endregion #region 3.1 自己优化的 修改方式(创建对象,直接修改) /// /// 3.1 自己优化的 修改方式(创建对象,直接修改) /// static void Edit2() { //1.查询出一个 要修改的对象 Customers _Customers = new Customers() { CustomerID = "zhang", Address = "洛阳西街", City = "洛阳", Phone = "1314520",
CompanyName = "微软", ContactName = "张学友" }; //2.将 对象 加入 EF容器,并获取 当前实体对象 的 状态管理对象 DbEntityEntryentry = db.Entry (_Customers); //3.设置 该对象 为被修改过 entry.State = System.Data.EntityState.Unchanged; //4.设置 该对象 的 ContactName属性 为 修改状态,同时 entry.State 被修改为 Modified 状态 entry.Property("ContactName").IsModified = true; //var u = db.Customers.Attach(_Customers); //u.ContactName = "郭富城"; //3.重新保存到数据库 -- ef 上下文 会 根据 实体对象的 状态 ,根据 entry.State =Modified 的值 生成 对应的 update sql 语句 db.SaveChanges(); Console.WriteLine("修改成功:"); Console.WriteLine(_Customers.ContactName); } #endregion
四、删除
#region 4.0 删除 -void Delete() ////// 4.0 删除 /// static void Delete() { //4.1创建要删除的 对象 Customers u = new Customers() { CustomerID = "zhang" }; //4.2附加到 EF中 db.Customers.Attach(u); //4.3标记为删除 注意:此方法 就是 起到了 标记 当前对象 为 删除状态 ! db.Customers.Remove(u); /* 也可以使用 Entry 来附加和 修改 DbEntityEntry entry = db.Entry */ //4.4执行删除sql db.SaveChanges(); Console.WriteLine("删除成功~~~"); } #endregion(u); entry.State = System.Data.EntityState.Deleted;
五、批处理
#region 5.0 批处理 -- 上下文 SaveChanges 方法 的 好处!!!! ////// 批处理 -- 上下文 SaveChanges 方法 的 好处!!!! /// static void SaveBatched() { //5.1新增数据 Customers _Customers = new Customers { CustomerID = "zou", Address = "洛阳西街", City = "洛阳", Phone = "1314520",
CompanyName = "微软", ContactName = "邹玉杰" }; db.Customers.Add(_Customers); //5.2新增第二个数据 Customers _Customers2 = new Customers { CustomerID = "zhao", Address = "洛阳西街", City = "洛阳", Phone = "1314520",
CompanyName = "微软", ContactName = "赵匡胤" }; db.Customers.Add(_Customers2); //5.3修改数据 Customers usr = new Customers() { CustomerID = "zhao", ContactName = "赵牧" }; DbEntityEntryentry = db.Entry (usr); entry.State = System.Data.EntityState.Unchanged; entry.Property("ContactName").IsModified = true; //5.4删除数据 Customers u = new Customers() { CustomerID = "zou" }; //4.2附加到 EF中 db.Customers.Attach(u); //4.3标记为删除 注意:此方法 就是 起到了 标记 当前对象 为 删除状态 ! db.Customers.Remove(u); db.SaveChanges(); Console.WriteLine("批处理 完成~~~~~~~~~~~~!"); } #endregion #region 5.1 批处理 -- 一次新增 50条数据 -void BatcheAdd() /// /// 5.1 批处理 -- 一次新增 50条数据 /// static void BatcheAdd() { for (int i = 0; i < 50; i++) { Customers _Customers = new Customers { CustomerID = "zou" + i, Address = "洛阳西街", City = "洛阳", Phone = "1314520",
CompanyName = "微软", ContactName = "邹玉杰" + i }; db.Customers.Add(_Customers); } db.SaveChanges(); } #endregion
通用数据库操作基类
我们看到这些数据库基本操作CRUD等,可以通过泛型提取出来放到父类里面,不需要每个不同的数据库操作类中都写一遍。
public class BaseDALwhere T:class,new() { /// /// 数据上下文对象 /// P05MODEL.LeaveWordBoradEntities db = new P05MODEL.LeaveWordBoradEntities(); #region 1.0 新增 实体 +int Add(T model) /// /// 新增 实体 /// /// /// public int Add(T model) { db.Set ().Add(model); return db.SaveChanges();//保存成功后,会将自增的id设置给 model的 主键属性,并返回受影响行数 } #endregion #region 2.0 根据 id 删除 +int Del(T model) /// /// 根据 id 删除 /// /// 包含要删除id的对象 /// public int Del(T model) { db.Set ().Attach(model); db.Set ().Remove(model); return db.SaveChanges(); } #endregion #region 3.0 根据条件删除 +int DelBy(Expression > delWhere) /// /// 3.0 根据条件删除 /// /// /// public int DelBy(Expression bool>> delWhere) { //3.1查询要删除的数据 List listDeleting = db.Set ().Where(delWhere).ToList(); //3.2将要删除的数据 用删除方法添加到 EF 容器中 listDeleting.ForEach(u => { db.Set ().Attach(u);//先附加到 EF容器 db.Set ().Remove(u);//标识为 删除 状态 }); //3.3一次性 生成sql语句到数据库执行删除 return db.SaveChanges(); } #endregion #region 4.0 修改 +int Modify(T model, params string[] proNames) /// /// 4.0 修改,如: /// T u = new T() { uId = 1, uLoginName = "asdfasdf" }; /// this.Modify(u, "uLoginName"); /// /// 要修改的实体对象 /// 要修改的 属性 名称 /// public int Modify(T model, params string[] proNames) { //4.1将 对象 添加到 EF中 DbEntityEntry entry = db.Entry (model); //4.2先设置 对象的包装 状态为 Unchanged entry.State = System.Data.EntityState.Unchanged; //4.3循环 被修改的属性名 数组 foreach (string proName in proNames) { //4.4将每个 被修改的属性的状态 设置为已修改状态;后面生成update语句时,就只为已修改的属性 更新 entry.Property(proName).IsModified = true; } //4.4一次性 生成sql语句到数据库执行 return db.SaveChanges(); } #endregion #region 4.0 批量修改 +int Modify(T model, Expression > whereLambda, params string[] modifiedProNames) /// /// 4.0 批量修改 /// /// 要修改的实体对象 /// 查询条件 /// 要修改的 属性 名称 /// public int ModifyBy(T model, Expression bool>> whereLambda, params string[] modifiedProNames) { //4.1查询要修改的数据 List listModifing = db.Set ().Where(whereLambda).ToList(); //获取 实体类 类型对象 Type t = typeof(T); // model.GetType(); //获取 实体类 所有的 公有属性 List proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList(); //创建 实体属性 字典集合 Dictionary<string, PropertyInfo> dictPros = new Dictionary<string, PropertyInfo>(); //将 实体属性 中要修改的属性名 添加到 字典集合中 键:属性名 值:属性对象 proInfos.ForEach(p => { if (modifiedProNames.Contains(p.Name)) { dictPros.Add(p.Name, p); } }); //4.3循环 要修改的属性名 foreach (string proName in modifiedProNames) { //判断 要修改的属性名是否在 实体类的属性集合中存在 if (dictPros.ContainsKey(proName)) { //如果存在,则取出要修改的 属性对象 PropertyInfo proInfo = dictPros[proName]; //取出 要修改的值 object newValue = proInfo.GetValue(model, null); //object newValue = model.uName; //4.4批量设置 要修改 对象的 属性 foreach (T usrO in listModifing) { //为 要修改的对象 的 要修改的属性 设置新的值 proInfo.SetValue(usrO, newValue, null); //usrO.uName = newValue; } } } //4.4一次性 生成sql语句到数据库执行 return db.SaveChanges(); } #endregion #region 5.0 根据条件查询 +List GetListBy(Expression > whereLambda) /// /// 5.0 根据条件查询 +List GetListBy(Expression > whereLambda) /// /// /// public List GetListBy(Expression bool>> whereLambda) { return db.Set ().Where(whereLambda).ToList(); } #endregion #region 5.1 根据条件 排序 和查询 + List GetListBy /// /// 5.1 根据条件 排序 和查询 /// /// 排序字段类型 /// 查询条件 lambda表达式 /// 排序条件 lambda表达式 /// public List GetListBy (Expression bool>> whereLambda, Expression > orderLambda) { return db.Set ().Where(whereLambda).OrderBy(orderLambda).ToList(); } #endregion #region 6.0 分页查询 + List GetPagedList /// /// 6.0 分页查询 + List GetPagedList /// /// 页码 /// 页容量 /// 条件 lambda表达式 /// 排序 lambda表达式 /// public List GetPagedList (int pageIndex, int pageSize, Expression bool>> whereLambda, Expression > orderBy) { // 分页 一定注意: Skip 之前一定要 OrderBy return db.Set ().Where(whereLambda).OrderBy(orderBy).Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList(); } #endregion }