Entity Framework高效查询优化:如何仅获取指定Revision关联数据?
EF查询优化方案:仅获取指定Revision的关联数据
问题根源
- 当前代码通过
GetAll拉取全部RevisionEEPROM实体及关联的Pages、PageLines到内存,再本地过滤指定ID的记录,完全浪费了数据库的查询优化能力,数据量越大性能越差。 - ViewModel中使用
.Result阻塞异步方法,容易引发死锁和线程卡顿问题。
优化步骤
1. 给通用数据服务增加过滤查询能力
在GenericDataService中新增支持Lambda过滤的方法,让筛选逻辑在数据库层面执行,只拉取需要的数据:
public async Task<IEnumerable<T>> GetWhere(Expression<Func<T, bool>> predicate, string[] includes = null) { using (var context = _contexFactory.CreateDbContext()) { var query = context.Set<T>().AsQueryable(); // 处理关联数据加载 if (includes != null) { foreach (var include in includes) query = query.Include(include); } // 应用过滤条件并异步加载结果 return await query.Where(predicate).ToListAsync(); } }
2. 修改数据服务的查询逻辑
修改GetEEPROMPages方法,直接查询指定ID的RevisionEEPROM,避免全量拉取:
public async Task<List<Page>> GetEEPROMPages(int eepromRevId) { // 只需指定最深层关联路径,EF会自动包含父级的Pages string[] includes = { "Pages.PageLines" }; // 直接在数据库筛选目标Revision var targetRevision = (await dataService.GetWhere(r => r.Id == eepromRevId, includes)).FirstOrDefault(); // 返回关联的Pages集合,空判断避免空引用异常 return targetRevision?.Pages.ToList() ?? new List<Page>(); }
3. 修复ViewModel的异步调用问题
替换.Result为await,避免线程阻塞:
// 若为UI事件处理方法可保留async void,其他场景建议用async Task private async void GetRevisionData(int revisionId) { List<Page> eepromPages = await revisionEEPROMDataService.GetEEPROMPages(revisionId); // 后续处理eepromPages逻辑 }
额外优化建议
- 投影查询:如果只需要
Page和PageLine的部分字段,可直接投影到DTO,减少数据库传输的数据量:public async Task<List<PageDto>> GetEEPROMPages(int eepromRevId) { using (var context = _contexFactory.CreateDbContext()) { return await context.Set<RevisionEEPROM>() .Where(r => r.Id == eepromRevId) .SelectMany(r => r.Pages) .Select(p => new PageDto { Id = p.Id, PageNumber = p.PageNumber, Lines = p.PageLines.Select(pl => new PageLineDto { Id = pl.Id, Content = pl.Content }).ToList() }) .ToListAsync(); } } - 无跟踪查询:如果查询到的实体不需要修改,可添加
.AsNoTracking()减少EF的实体跟踪开销:var query = context.Set<T>().AsNoTracking().AsQueryable();
内容的提问来源于stack exchange,提问作者Michael
相关产品推荐
相关产品推荐

