刚开始接触EF框架的时候总是不明白:
为什么查询出来的对象 Remove()、再 SaveChanges()就会把数据删除。而自己 new 一个Person()对象,然后 Remove()不行?
为什么查询出来的对象修改属性值后、再 SaveChanges()就会把数据库中的数据修改?
随着慢慢的深入研究和网上查找资料就明白了,原来EF的背后还有一套自己的对象状态管理体系。
在EF中的对象有五个状态:
1、Detach(游离态,脱离态)
--> 自己动手new出来的对象就是处于Detach状态的
2、Unchange(未改变)
--> 当你使用EF框架进行查询的时候,查询出来的对象都是处于这个状态
3、Added(新增)
--> 一个自己new出来的对象想要加入数据库中,必须首先要转换到这个状态
4、Deleted(删除)
--> 要对从EF框架中查询出来的对象进行删除操作的话,要首先转换到此状态下
5、Modified(被修改)
--> 对从EF框架中查询出来的对象进行改动后,对象会处于此状态下
他们之间转换的关系与途径大致可以用下面这幅图来描述:
从图中可以看出,一共有两个入口:
1、直接new
2、使用EF进行查询
只有使用这两种方法拿到了对象以后才能进行图中一系列的转换操作。
当然,在实际的应用中我们也可以强制改变对象的状态,不经过执行Add()、Delete()等函数操作。
这是因为,当 SavaChanged()方法执行期间,会查看当前对象的 EntityState 的值,决定是去新增(Added)、修改(Modified)、删除(Deleted)或者什么也不做(UnChanged)
使用方法如下:
var p = new Person();
p.Id = 2;
ctx.Entry(p).State = System.Data.Entity.EntityState.Unchanged;
(更新、删除等都是根据Id 进行的)
目前所知道的几个关于EF优化的方法:
1) 如果查询出来的对象只是供显示使用,不会修改、删除后保存,那么可以使用AsNoTracking()来使得查询出来的对象是 Detached 状态,这样对对象的修改也还是 Detached状态,EF 不再跟踪这个对象状态的改变,能够提升性能,因为在管理对象状态的过程中也是需要消耗的。
2) 如果要批量删除某表中的数据,如果查询出来一个个 Remove() 的话,性能就太坑爹了,在考虑性能的前提下可以使用原生的SQL语句来执行批量删除操作,用法如下:
ctx.Database.ExecuteSqlCommand("update T_DeputyUserPerms set IsDeleted=true where DeputyUserId={0}", DeputyUserId);
--> 注:使用ef框架执行的sql都采用参数化执行sql语句的方式,防止sql注入式漏洞,更安全。(通过查看生成的sql语句可以直观地发现)