标签:== 问题 efault write instance microsoft entry 更改 排序
对象映射关系对数据库进行操作,解决面向对象与关系数据库不匹配的现象。
1.1 ORM性能问题
1.2 EF的状态管理
在程序中实现数据的增、删、改操作,EF会监控这些状态的变化,在执行SaveChange()方法时,会根据对象状态的变化执行相应的操作。
using (MySchoolContext db = new MySchoolContext()) { Grade grade = new Grade() { GradeName = "Y3" }; //输出当前对象状态 Console.WriteLine(db.Entry(grade).State); //通过Entry()方法获取模型状态
db.Grade.Add(grade); Console.WriteLine(db.Entry(grade).State);
db.SaveChanges(); Console.WriteLine(db.Entry(grade).State); } |
方法或属性 |
说明 |
CurrentValues |
获取由此对象表示的跟踪实体的当前属性值 |
OriginalValues |
获取由此对象表示的跟踪实体的原始属性值 |
State |
获取或设置实体的状态 |
Reload() |
从数据库重新加载对象的值 |
其中,State属性是一个EntityState枚举类型,其取值如下:
Detached | 表示对象存在,但没有被跟踪 |
Unchanged | 表示对象尚未经过修改 |
Added | 表示对象为新对象,并且已添加到对象上下文 |
Deleted | 对象已从对象上下文中删除 |
Modified | 表示对象的一个标量属性已更改 |
1.3查询不进行跟踪
using (MySchoolContext db = new MySchoolContext()) { var result = db.Student.AsNoTracking().FirstOrDefault(); Console.WriteLine(db.Entry(result).State); } |
using (MySchoolContext db = new MySchoolContext()) { //禁用自动跟踪变化 db.Configuration.AutoDetectChangesEnabled = false; for (int i = 0; i < 5000; i++) { var stu = new Student() { StudentName = "alex", GradeId = 1, Age = 20 }; db.Student.Add(stu); } db.SaveChanges(); } |
在使用EF修改或删除数据时,必须先查询对象,然后再对其进行修改或删除。然而现实开发中很多情况都是通过主键删除一条数据。我们可以通过实体的状态特性来进行优化。
using (MySchool1Entities entities = new MySchool1Entities()) { //创建替身对象 var stu = new Student { StudentNo = "10001" }; //给实体附加到上下文中 entities.Student.Attach(stu); //删除 entities.Student.Remove(stu); entities.SaveChanges(); } |
代码中的Attach()方法可以将EntityState.Unchangee状态的对象附加到上下文中。
每次调用时再去查询,两个条件:①Poco类是Public且不能为Sealed。 ②导航属性需要标记为Vritual。
一次性将数据读取出来,从缓存中读取,不用在查询数据库,两个条件:①先关闭延迟加载。 ②查询主表的同时通过Include把从表数据也查询出来。
--步骤:①单个实体用:Reference ②集合用:Collection ③最后需要Load一下
注意:默认用延迟,多次读数据库用贪婪。
//延迟加载 using (dbContext1 db = new dbContext1()) { Console.WriteLine("---------------- 01-延迟加载 ---------------"); //EF默认就是延迟加载,默认下面的语句就是true,关闭则false db.Configuration.LazyLoadingEnabled = true;
var list = db.Student.ToList(); //此处加载的数据,没有对从表进行任何查询操作 foreach (var stu in list) { Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName); //下面调用导航属性(一对一的关系) 每次调用时,都要去查询数据库 var stuAddress = stu.StudentAddress; Console.WriteLine("地址编号:{0},地址名称:{1}", stuAddress.studentAddressId, stu.studentName); } } |
//贪懒加载 using (dbContext1 db = new dbContext1()) { Console.WriteLine("------------------- 03-立即加载 ------------------");
//1.关闭延迟加载 db.Configuration.LazyLoadingEnabled = false;
//2. 获取主表数据的同时,通过Include将从表中的数据也全部加载出来 var list = db.Student.Include("StudentAddress").ToList(); foreach (var stu in list) { Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName); //这里获取从表中的数据,均是从缓存中获取,无需查询数据库 var stuAddress = stu.StudentAddress; Console.WriteLine("地址编号:{0},地址名称:{1}", stuAddress.studentAddressId, stu.studentName); } } |
//显示加载 using (dbContext1 db = new dbContext1()) { Console.WriteLine("----------------- 04-显式加载 ------------------"); //1.关闭延迟加载 db.Configuration.LazyLoadingEnabled = false;
//2.此处加载的数据,不含从表中的数据 var list = db.Student.ToList(); foreach (var stu in list) { Console.WriteLine("学生编号:{0},学生姓名:{1}", stu.studentId, stu.studentName); //3.下面的这句话,可以开启重新查询一次数据库 //3.1 单个属性的情况用Refercence db.Entry<Student>(stu).Reference(c => c.StudentAddress).Load(); //3.2 集合的情况用Collection //db.Entry<Student>(stu).Collection(c => c.StudentAddress).Load();
//下面调用导航属性(一对一的关系) 每次调用时,都要去查询数据库 var stuAddress = stu.StudentAddress; Console.WriteLine("地址编号:{0},地址名称:{1}", stuAddress.studentAddressId, stu.studentName); } } |
using (DbContext db = new CodeFirstModel()) { //增加 TestInfor t1 = new TestInfor() { id = Guid.NewGuid().ToString("N"), txt1 = "txt1", txt2 = "txt2" }; db.Set<TestInfor>().Add(t1); //删除 TestInfor t2 = db.Set<TestInfor>().Where(u => u.id == "1").FirstOrDefault(); if (t2 != null) { db.Set<TestInfor>().Remove(t2); } //修改 TestInfor t3 = db.Set<TestInfor>().Where(u => u.id == "3").FirstOrDefault(); t3.txt2 = "我是李马茹23";
//SaveChanges事务提交 int n = db.SaveChanges(); //一次性统一或回滚 Console.WriteLine("数据作用条数:" + n); } |
using (DbContext db = new CodeFirstModel()) { DbContextTransaction trans = null; try { //开启事务 trans = db.Database.BeginTransaction(); //多个SaveChanges //增加 string sql1 = @"insert into TestInfor values(@id,@txt1,@txt2)"; SqlParameter[] pars1 ={ new SqlParameter("@id",Guid.NewGuid().ToString("N")), new SqlParameter("@txt1","txt11"), new SqlParameter("@txt2","txt22") }; db.Database.ExecuteSqlCommand(sql1, pars1); //删除 string sql2 = @"delete from TestInfor where id=@id"; SqlParameter[] pars2 ={ new SqlParameter("@id","22") }; db.Database.ExecuteSqlCommand(sql2, pars2); //修改 string sql3 = @"update TestInfor set txt1=@txt1 where id=@id"; SqlParameter[] pars3 ={ new SqlParameter("@id","3"), new SqlParameter("@txt1","二狗子") }; db.Database.ExecuteSqlCommand(sql3, pars3);
//提交事务 trans.Commit(); Console.WriteLine("事务成功了"); } catch (Exception ex) { Console.WriteLine(ex.Message); trans.Rollback(); //回滚
} finally { //也可以把该事务写到using块中,让其自己托管,就不需要手动释放了 trans.Dispose(); } } |
using (DbContext db = new CodeFirstModel()) { //自动脱管,不需要手动释放 多数据库连接 using (DbContextTransaction trans = db.Database.BeginTransaction()) { try { TestInfor t1 = new TestInfor() { id = Guid.NewGuid().ToString("N"), txt1 = "111111111", txt2 = "222222222222" }; db.Entry(t1).State = EntityState.Added; db.SaveChanges();
TestInfor t2 = new TestInfor() { id = Guid.NewGuid().ToString("N") + "123", txt1 = "111111111", txt2 = "222222222222" }; db.Entry(t2).State = EntityState.Added; db.SaveChanges();
trans.Commit(); } catch (Exception) { trans.Rollback(); } } } |
EF在DbContext类的Database属性里提供了ExecuteSqlCommand()和SqlQuery()两个方法,用来直接访问数据库。
using (MySchool1Entities db = new MySchool1Entities()) { //执行update语句 string sql = "update grade set gradeName=@gradeName where gradeId=@gradeId"; SqlParameter[] ps = { new SqlParameter("@gradeName","第二学年"), new SqlParameter("@gradeId",3) }; int result=db.Database.ExecuteSqlCommand(sql, ps); //返回影响行数 if (result>0) { Console.WriteLine("数据更新完成!"); } //执行查询语句 sql = "select * from from student where studentNo=@stuNo"; ps = new SqlParameter[] { new SqlParameter("@stuNo", "S1001234") }; var stu = db.Database.SqlQuery<Student>(sql, ps); //返回集合 Console.WriteLine(stu.ToList()[0]); } |
public class BaseDAL<T> where T:class 2 { 3 private DbContext db 4 { 5 get 6 { 7 DbContext dbContext = CallContext.GetData("dbContext") as DbContext; 8 if (dbContext == null) 9 { 10 dbContext = new MySchoolContext(); 11 CallContext.SetData("dbContext", dbContext); 12 } 13 return dbContext; 14 } 15 } 16 17 /// <summary> 18 /// 执行增加,删除,修改操作(或调用存储过程) 19 /// </summary> 20 /// <param name="sql"></param> 21 /// <param name="pars"></param> 22 /// <returns></returns> 23 public int ExecuteSql(string sql, params SqlParameter[] pars) 24 { 25 return db.Database.ExecuteSqlCommand(sql, pars); 26 } 27 28 /// <summary> 29 /// 执行查询操作 30 /// </summary> 31 /// <typeparam name="T"></typeparam> 32 /// <param name="sql"></param> 33 /// <param name="pars"></param> 34 /// <returns></returns> 35 public List<T> ExecuteQuery(string sql, params SqlParameter[] pars) 36 { 37 return db.Database.SqlQuery<T>(sql, pars).ToList(); 38 } 39 40 /// <summary> 41 /// 添加 42 /// </summary> 43 /// <param name="model"></param> 44 /// <returns></returns> 45 public int Add(T model) 46 { 47 db.Set<T>().Add(model); 48 return db.SaveChanges(); 49 } 50 51 /// <summary> 52 /// 删除(适用于先查询后删除的单个实体) 53 /// </summary> 54 /// <param name="model">需要删除的实体</param> 55 /// <returns></returns> 56 public int Del(T model) 57 { 58 db.Set<T>().Attach(model); 59 db.Set<T>().Remove(model); 60 return db.SaveChanges(); 61 } 62 63 /// <summary> 64 /// 根据条件删除(支持批量删除) 65 /// </summary> 66 /// <param name="delWhere">传入Lambda表达式(生成表达式目录树)</param> 67 /// <returns></returns> 68 public int DelBy(Expression<Func<T, bool>> delWhere) 69 { 70 var listDels = db.Set<T>().Where(delWhere); 71 foreach(var model in listDels) 72 { 73 db.Set<T>().Attach(model); 74 db.Set<T>().Remove(model); 75 } 76 return db.SaveChanges(); 77 } 78 79 /// <summary> 80 /// 修改 81 /// </summary> 82 /// <param name="model">修改后的实体</param> 83 /// <returns></returns> 84 public int Modify(T model) 85 { 86 db.Entry(model).State = EntityState.Modified; 87 return db.SaveChanges(); 88 } 89 90 /// <summary> 91 /// 批量修改 92 /// </summary> 93 /// <param name="model">要修改实体中 修改后的属性 </param> 94 /// <param name="whereLambda">查询实体的条件</param> 95 /// <param name="proNames">lambda的形式表示要修改的实体属性名</param> 96 /// <returns></returns> 97 public int ModifyBy(T model, Expression<Func<T, bool>> whereLambda, params string[] proNames) 98 { 99 List<T> listModifes = db.Set<T>().Where(whereLambda).ToList(); 100 Type t = typeof(T); 101 List<PropertyInfo> proInfos = t.GetProperties(BindingFlags.Instance | BindingFlags.Public).ToList(); 102 Dictionary<string, PropertyInfo> dicPros = new Dictionary<string, PropertyInfo>(); 103 proInfos.ForEach(p => 104 { 105 if (proNames.Contains(p.Name)) 106 { 107 dicPros.Add(p.Name, p); 108 } 109 }); 110 foreach (string proName in proNames) 111 { 112 if (dicPros.ContainsKey(proName)) 113 { 114 PropertyInfo proInfo = dicPros[proName]; 115 object newValue = proInfo.GetValue(model, null); 116 foreach (T m in listModifes) 117 { 118 proInfo.SetValue(m, newValue, null); 119 } 120 } 121 } 122 return db.SaveChanges(); 123 } 124 125 /// <summary> 126 /// 根据条件查询 127 /// </summary> 128 /// <param name="whereLambda">查询条件(lambda表达式的形式生成表达式目录树)</param> 129 /// <returns></returns> 130 public IQueryable<T> GetListBy(Expression<Func<T, bool>> whereLambda) 131 { 132 return db.Set<T>().Where(whereLambda); 133 } 134 /// <summary> 135 /// 根据条件排序和查询 136 /// </summary> 137 /// <typeparam name="Tkey">排序字段类型</typeparam> 138 /// <param name="whereLambda">查询条件</param> 139 /// <param name="orderLambda">排序条件</param> 140 /// <param name="isAsc">升序or降序</param> 141 /// <returns></returns> 142 public IQueryable<T> GetListBy<Tkey>(Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) 143 { 144 if (isAsc) 145 { 146 return db.Set<T>().Where(whereLambda).OrderBy(orderLambda); 147 } 148 else 149 { 150 return db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda); 151 } 152 } 153 /// <summary> 154 /// 分页查询 155 /// </summary> 156 /// <typeparam name="Tkey">排序字段类型</typeparam> 157 /// <param name="pageIndex">页码</param> 158 /// <param name="pageSize">页容量</param> 159 /// <param name="whereLambda">查询条件</param> 160 /// <param name="orderLambda">排序条件</param> 161 /// <param name="isAsc">升序or降序</param> 162 /// <returns></returns> 163 public IQueryable<T> GetPageList<Tkey>(int pageIndex, int pageSize, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) 164 { 165 166 IQueryable<T> list = null; 167 if (isAsc) 168 { 169 list = db.Set<T>().Where(whereLambda).OrderBy(orderLambda) 170 .Skip((pageIndex - 1) * pageSize).Take(pageSize); 171 } 172 else 173 { 174 list = db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda) 175 .Skip((pageIndex - 1) * pageSize).Take(pageSize); 176 } 177 return list; 178 } 179 /// <summary> 180 /// 分页查询输出总行数 181 /// </summary> 182 /// <typeparam name="Tkey">排序字段类型</typeparam> 183 /// <param name="pageIndex">页码</param> 184 /// <param name="pageSize">页容量</param> 185 /// <param name="whereLambda">查询条件</param> 186 /// <param name="orderLambda">排序条件</param> 187 /// <param name="isAsc">升序or降序</param> 188 /// <returns></returns> 189 public IQueryable<T> GetPageList<Tkey>(int pageIndex, int pageSize, out int rowCount, Expression<Func<T, bool>> whereLambda, Expression<Func<T, Tkey>> orderLambda, bool isAsc = true) 190 { 191 IQueryable<T> list = null; 192 rowCount = db.Set<T>().Where(whereLambda).Count(); 193 if (isAsc) 194 { 195 list = db.Set<T>().Where(whereLambda).OrderBy(orderLambda) 196 .Skip((pageIndex - 1) * pageSize).Take(pageSize); 197 } 198 else 199 { 200 list = db.Set<T>().Where(whereLambda).OrderByDescending(orderLambda) 201 .Skip((pageIndex - 1) * pageSize).Take(pageSize); 202 } 203 return list; 204 } 205 206 207 }
深入理解ADO.NET Entity Framework(02)
标签:== 问题 efault write instance microsoft entry 更改 排序
原文地址:https://www.cnblogs.com/shishixiang/p/14024465.html