EF 6.4中ToBindingList()方法执行极慢的原因及优化方案
EF 6.4 绑定DataGridView ToBindingList()性能瓶颈优化方案
你遇到的28秒耗时瓶颈来自EF 6内置Local.ToBindingList()的实现逻辑:该方法会为每个被上下文跟踪的实体注册属性变更监听事件,同时全程和EF变化跟踪逻辑联动,6.5万条数据规模下,这部分非必要开销被大幅放大。
场景1:仅需展示数据,无需将界面编辑结果同步回EF上下文
绝大多数全量加载绑定场景都属于该类,直接放弃Local和EF内置的ToBindingList()即可,优化后全流程耗时可压到2秒以内,与DataSet方案性能持平:
private async void button1_Click(object sender, EventArgs e) { Stopwatch sw = Stopwatch.StartNew(); List<SolarDataLog> dataList; using (var ent = new MYHOMEEntities()) { // 加AsNoTracking关闭变化跟踪,进一步降低查询开销 dataList = await ent.SolarDataLog.AsNoTracking().ToListAsync(); } // 数据查询耗时约1-1.5秒 MessageBox.Show(sw.ElapsedMilliseconds.ToString()); sw.Restart(); // 手动初始化BindingList,耗时通常低于100ms var table = new BindingList<SolarDataLog>(dataList); MessageBox.Show(sw.ElapsedMilliseconds.ToString()); sw.Restart(); dataGridView1.DataSource = table; MessageBox.Show(sw.ElapsedMilliseconds.ToString()); }
场景2:需要双向绑定,编辑后需通过EF上下文保存数据
如果确实需要编辑数据并同步回EF上下文,可通过关闭自动变化检测+BindingSource包装的方式绕过ToBindingList()的高开销:
private async void button1_Click(object sender, EventArgs e) { Stopwatch sw = Stopwatch.StartNew(); var ent = new MYHOMEEntities(); // 临时关闭自动变化检测,减少加载阶段的额外校验开销 ent.Configuration.AutoDetectChangesEnabled = false; await ent.SolarDataLog.LoadAsync(); MessageBox.Show(sw.ElapsedMilliseconds.ToString()); sw.Restart(); // 用BindingSource直接包装Local集合,无需调用ToBindingList() var bindingSource = new BindingSource { DataSource = ent.SolarDataLog.Local }; // 该步骤耗时可降到1秒以内 MessageBox.Show(sw.ElapsedMilliseconds.ToString()); sw.Restart(); dataGridView1.DataSource = bindingSource; // 后续需要执行SaveChanges操作前,再把自动变化检测改回true即可 // ent.Configuration.AutoDetectChangesEnabled = true; MessageBox.Show(sw.ElapsedMilliseconds.ToString()); }
额外优化建议
如果业务允许,优先实现DataGridView分页加载逻辑,每次仅加载当前页的几十到上百条数据,无论是加载速度还是界面操作流畅度都会有质的提升。
内容的提问来源于stack exchange,提问作者SZL
相关产品推荐
相关产品推荐

