EF数据操作比较详解

42次阅读

共计 2024 个字符,预计需要花费 6 分钟才能阅读完成。

1. 数据 Load

延迟加载:当实体第一次读取时,相关数据没有加载;当第一次试图访问导航属性时,所需的导航数据自动加载,EF 默认使用这种方式加载数据,尽量使用预先加载和显示加载。
优点: 加载数据快
缺点:数据库交互多次

预先加载:当读取实体时,相关数据同时读取。这通常会导致一个连接查询,查询所有所需的数据,使用 Include 方法指定预先加载。
优点: 数据库交互少
缺点:加载实体多,数据量大时,变慢,会有很多冗余字段

显示加载:这种加载方式类似于延迟加载,不同的是我们要在代码中明确地查询相关数据,导航属性是手动控制的,需要调用 Collection.Load 方法获取集合,调用 Reference.Load 方法获取单个实体来加载相关数据。
优点: 加载数据快,导航属性如何加载可以自己控制,通常关联实体集合的数量被限制时,使用 Load 方法
缺点:需要自己控制,数据库交互多次,交互次数由自己控制

CompiledQuery:提供对查询的编译和缓存以供重新使用。当相同的查询需要执行很多遍的时候,那么我们可以使用 ComplieQuery 将查询的语句进行编译以便下次使用,这样可以免去对同一语句的多次处理,从而改善性能
优点:减少查询表达式树编译次数

AsNoTracking:如果数据是只读操作,用 AsNoTracking 取消追踪,提升性能。
SqlQuery:对于复杂的查询或存储过程的使用,考虑用 SqlQuery 操作原生 sql。
Skip:分页在数据库中分页,不要再内存中分页,以提升性能

IQueryable 和 IEnumerable:IQueryable 返回的是查询表达式,也就是说生成了 SQL 查询语句但是却还没有与数据库进行交互。IEnumerable 则是已经执行查询数据库的操作且数据保存在了内存中,所以在进行条件拼接的时候一定要在 IQueryable 类型后面追加 Where 条件语句,而不是等到 ToList 之后再开始写条件,以提升性能。
2. 数据 Get

Find()方法:查找一个实体,不仅查询数据库,而且还查询新添加的没有保存到数据库中的对象。
查找方式:内存查找 -> 新添加还没保存到数据库中的对象 -> 数据库中还没加载到内存中实体
优点:根据主键查找,主键有索引,速度快
缺点:只能根据主键查找

GetObjectByKey()方法:查找一个实体
查找方式:内存查找 - > 数据库中实体
优点:先从内存中取速度快

缺点:只能根据主键查找,查询不到抛出异常
TryGetObjectByKey()方法:查找一个实体
查找方式:内存查找 - > 数据库中实体
优点:先从内存中取速度快 , 查询不到返回 null
缺点:只能根据主键查找

Single() 方法:查找一个实体
查找方式:数据库中实体
优点:不根据主键进行查询或查询时加载相关实体
缺点:查询没有返回结果或返回的结果多于一个就会抛出异常

SingleOrDefault() 方法:查找一个实体
查找方式:数据库中实体
优点:不根据主键进行查询或查询时加载相关实体, 查询没有返回结果返回 null
缺点:返回的结果多于一个就会抛出异常

First() 方法:查找一个实体,不关心是否有多个结果,仅仅取得第一条
查找方式:数据库中实体
优点:不根据主键进行查询或查询时加载相关实体, 只取第一条
缺点:查询没有结果就会抛出异常

FirstOrDefault() 方法:查找一个实体,不关心是否有多个结果,仅仅取得第一条
查找方式:数据库中实体
优点:不根据主键进行查询或查询时加载相关实体, 只取第一条,查询没有结果返回 null
缺点:不知道是否有多条数据
3. 其它优化
事物的简短性:尽量把查询语句和影响事物的语句放在事物外面执行,防止资源死锁。
批量修改:尽量用 sql 执行
预生成视图:在实体框架可以针对概念模型执行查询或将更改保存到数据源之前,它必须生成一组本地查询视图才能访问数据库。由于生成这些视图会产生很高的成本,因此,您可以在设计时预生成视图并将它们添加到项目。预生成视图方式参考:
https://msdn.microsoft.com/zh-cn/library/bb896240.aspx

AsEnumerable() 和 ToList():两者都是延迟执行 sql,区别是 AsEnumerable() 在执行过滤之前,先将所有数据放到内存中,再进行筛选;ToList() 则是先拼接成 sql 再请求数据库,然后结果放入内存,是真正的筛选数据。

IQueryable 和 IEnumberable:IQueryable 实现了 IEnumberable 接口,IEnumerable<T> 泛型类在调用自己的 SKip 和 Take 等扩展方法之前数据就已经加载在本地内存里了,IEnumerable 跑的是 Linq to Object,强制从数据库中读取所有数据到内存先,而 IQueryable<T> 是将 Skip ,Take 这些方法表达式翻译成 T -SQL 语句之后再向 SQL 服务器发送命令,它并不是把所有数据都加载到内存里来才进行条件过滤。

正文完
 0