目录
EF Core 默认会对通过上下文查询出来的所有实体类进行,以便于在执行 SaveChanges 的时候把实体类的改变同步到数据库中。上下文不仅会跟踪对象的状态改变,还会通过快照的方式记录实体类的原始值,这是比较消耗资源的。因此,如果开发人员能够确认通过上下文查询出来的对象只是用来展示,不会发生状态改变,那么可以使用AsNoTracking 方法告诉IQueryable 在查询的时候“禁用跟踪”。
Book[] books=ctx.Books,AsNoTracking()Take(3).ToArray();
Book bl=books[0];
bl.Title="abc";
EntityEntry entryl = ctx.Entry(bl);
Console.WriteLine(entryl.State);
上面代码的执行结果是“Detached”,也就说使用AsNoTracking 查询出来的实体类是不被上下文跟踪的。因此,在项目开发的时候,如果我们查询出来的对象不会被修改、删除等,那么在查询的时候,可以启用AsNoTraking,这样就能降低EF Core的资源占用。
当使用EF Core 从数据库中根据 Id 获取数据的时候,我们还可以使用同步的Fid 方法或者异步的FindAsync法。Find或者FindAsync方法会先在上下文查找这个对象是否已经被跟如果对象已经被跟踪,就直接返回被跟踪的对象,只有在本地没有找到这个对象时,EF Core才去数据库查询,而Single方法则一直都是执行一次数据库查询。因此用Find 方法有可能少一次数据库查询,性能更好。但是如果在对象被跟踪之后,数据库中对应的数据已经被其程序修改了,则Find方法可能会返回旧数据
在EFCore 中,我们可以给对应实体类设置一个全局查询筛选器,这样所有的查询都会自动增加全局查询筛选器,被软删除的数据就会自动从查询结果中过滤掉。全局查询筛选器可以让开发人员专注于编写业务逻辑代码,而不用操心软删除数据的滤。当然,使用软删除的时候,我们需要注意其对性能的影响。如果启用了软删除,查询餐可能会导致全表扫描,从而影响查询性能,而如果为软删除列创建索引的话,又会增加索引“磁盘占用。正因为如此,如果使用了全局查询筛选器,我们就需要根据项目的需要进一步优化数据库。
为了避免多个用户同时操作资源造成的并发冲突问题,我们通常会进行并发控制。并发控制有很多种实现方式,在数据库层面有“悲观”和“乐观”两种策略。悲观并发控制一般采用行锁、表锁等排他锁对资源进行锁定,确保同时只有一个使用者操作被锁定的资源:乐观并发控制则允许多个使用者同时操作同一个资源,通过冲突的检测避免并发操作。
因为不同类型的数据库对于悲观并发控制的实现差异很大,所以EFCore 没有封装悲观发控制,需要开发人员编写原生 SQL 语句。
悲观并发控制的使用比较简单,只要对要进行并发控制的资源加上锁即可。但是这种锁是独占排他的,如果系统并发量很大,锁会严重影响性能,如果使用不当,甚至会导致死锁。因机,这里只是用1s此,对于高并发系统,要尽量优化算法,比如调整逻辑或者使用 NoSQL 等,尽量避免通过关系数据库进行并发控制。如果必须使用数据库进行并发控制,尽量采用乐观并发控制。
EF Core 内置了使用并发令牌列实现的乐观并发控制,乐观并发控制能够避免悲观锁带来的性能下降、死锁等问题,因此作者推荐使用乐观并发控制而不是悲观锁。如果有一个确定的字段要被进行并发控制,使用ISConcurrencyToken 把这个字段设置为并发令牌即可;如果无法确定唯一的并发令牌列,可以引入一个额外的属性并将其设置为并发令牌,并且在每次更新数据的时候,手动更新这一列的值:当然,如果用的是Microson soL Server 数据库,我们也可以采用 RowVersion 列,这样就不用开发人员手动更新并发令牌列的值了。