EF(EFCore)性能优化与高级用法

1、使用AsNoTracking()

使用AsNoTracking()后,将不监听对象的状态(是否被改变);当确定查询出来的数据不会改变的时候使用AsNoTracking();

使用context.Entry<User>(user).State 查看对象监听状态。

关闭所有监听:context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
开启所有监听:context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.TrackAll;

2、正确使用Find(id=10)来代替FirstOrDefault(t=>t.id=10)

Find会优先查询缓存,当前面已经查询过这条数据的时候使用,而FirstOrDefault每次都会查询数据库;当id=10的数据被修改之后,find查出的数据是新数据。

3、正确区分IQueryableIEnumerable

3.1 IEnumerable(linq to object)用于操作内存对象。是个迭代器的实现。

3.1.1 Where(t=>t.id>10)中的“t=>t.id>10”是个委托
3.1.2 封装的函数的时候将返回值设为IEnumerable<T>,即使返回return IQueryable<T>也会立刻查询数据库

3.2 IQueryable(linq to sql)用于操作数据库,且继承了IEnumerableIQueryable中实现了表达式目录树(Expression),IQueryProvider根据表达式目录树来构建sql语句。

3.2.1 Where(t=>t.id>10)中的“t=>t.id>10”是个表达式目录树
3.2.2 AsEnumerable()AsQueryable()如果后面不继续跟过滤条件等,效果是一样的。 如果后面加了Where / Select / Take() /Skip 等条件,AsEnumerable()先查数据库再过滤,AsQueryable()将条件生成sql,一起在数据库中过滤。

4、正确使用导航属性 和 延迟查询(延迟加载)

在主表对象中包含一个子表集合对象的属性就是导航属性。跟数据库中的主外键设置无关。

利用延迟加载可以叠加多次查询条件,一次性提交给数据库。

使用建议:在开发中不确定后面是否需要关联表数据,可以使用延迟加载来按需获取数据。

4.1 导航属性要延迟加载必须具备两个条件:

a、导航属性是virtual的;
b、延迟查询必须是开启的。

EF:context.Configuration.LazyLoadingEnabled=true; (默认就是true的)

EF Core:

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    if (!optionsBuilder.IsConfigured)
        var builder = optionsBuilder.UseSqlServer(_connStr);
 
    optionsBuilder.UseLazyLoadingProxies(); //启用延迟加载
 
}

4.2 延迟查询关闭之后可以使用显示加载的方式:

加载集合: context.Entry<Company>(company).Collection(t=>t.Users).Load();

加载单个: context.Entry<Company>(company).Reference(t=>t.Users).Load();

4.3 使用ToList()的时候会立马执行数据库sql查询,看到过很多同学先ToList()再Where()过滤。

其它的还有:Count()FirstOrDefault()、迭代器IEnumerable/foreach 等都会立刻执行sql。

封装函数的时候可以返回IQueryable<T>,而不是IEnumable<T>,防止立马查询数据库。

4.4 迭代(如foreach)使用延迟查询的时候,迭代完了才关闭链接,应当避免使用这种场景。可以在迭代之前ToList()

4.6 延迟加载的对象(IQueryable<T>)脱离了DbContext上下文对象的范围后不能被查询,因为DbContext被释放了。

5、预先加载

使用Include,查询主表时把子表(导航属性)也一次性查出来。延迟查询关闭后也不影响的。

例如:context.Set<Company>().Include("Users").Where(t=>t.id<10);

使用建议:当开发中能确定后面一定会用到子表数据的时候可以使用预先加载。

6、使用TransactionScope

TransactionScope可以完成多个context多个SaveChange的事务问题,默认一个SaveChange是一个事务

还可以使用context.Database.BeginTransaction做单库事务。

using (DbContext context = new DbContext())
{
    using (TransactionScope tran = new TransactionScope())
    {
        context.SaveChange();
        context.SaveChange();
        //无异常会执行Complete 提交事务
        tran.Complete();
    }
}

7、添加Z.EntityFramework.Plus.EFCore依赖使用一些特殊的语法

这个是免费的,但 Z.EntityFramework.Plus的一些批量数据操作的包是收费的

7.1 EFCore删除必须先查询再删除,优化后可直接删除:context.User.Where(t => t.Id == 100).Delete();

7.2 优化更新语句:context.User.Where(t => t.Id == 4).Update(t =>new User() { NickName = "2224114" ,Phone = "1234"} );

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值