使用Entity Framework Core一次性获取多表数据填充SelectList的方法
当然有更优化的方案!你当前的写法确实会触发4次独立的数据库查询,每次都要和数据库建立往返,在高并发场景下会额外消耗数据库资源和网络时间。我们可以从减少数据库往返次数、优化数据加载这两个方向来改进:
优化方案1:异步并行加载,减少总耗时
首先推荐使用异步编程模型(ASP.NET Core页面/控制器的异步方法是最佳实践),通过并行加载所有需要的数据集,让数据库可以同时处理这些查询,总耗时会远小于串行执行四次查询的时间。同时,我们只选择需要的Id和Nome字段,避免加载整个实体的冗余数据:
public async Task OnGetAsync() { // 启动四个并行的查询任务,只获取需要的字段 var celulasTask = _context.Celulas.Select(c => new { c.Id, c.Nome }).ToListAsync(); var uapTask = _context.UAP.Select(u => new { u.Id, u.Nome }).ToListAsync(); var referenciasTask = _context.Referencias.Select(r => new { r.Id, r.Nome }).ToListAsync(); var celulaTiposTask = _context.CelulaTipos.Select(ct => new { ct.Id, ct.Nome }).ToListAsync(); // 等待所有查询完成 await Task.WhenAll(celulasTask, uapTask, referenciasTask, celulaTiposTask); // 构建SelectList并赋值给ViewData ViewData["CelulaId"] = new SelectList(await celulasTask, "Id", "Nome"); ViewData["UAPId"] = new SelectList(await uapTask, "Id", "Nome"); ViewData["ReferenciaId"] = new SelectList(await referenciasTask, "Id", "Nome"); ViewData["CelulaTipoId"] = new SelectList(await celulaTiposTask, "Id", "Nome"); }
优化方案2:添加缓存,彻底减少数据库查询
如果这些下拉列表的数据是不经常变动的基础数据(比如分类、类型这类静态数据),可以把这些数据缓存到内存中,后续请求直接从缓存读取,完全避免数据库查询:
首先需要注入IMemoryCache(在页面模型的构造函数中):
private readonly YourDbContext _context; private readonly IMemoryCache _cache; public YourPageModel(YourDbContext context, IMemoryCache cache) { _context = context; _cache = cache; }
然后修改OnGetAsync方法:
public async Task OnGetAsync() { // 定义缓存键,确保唯一 var cacheKey = "Dropdown_SelectLists_Data"; // 从缓存获取数据,不存在则查询数据库并缓存 var dropdownData = await _cache.GetOrCreateAsync(cacheKey, async entry => { // 设置缓存过期时间,根据数据更新频率调整(比如1小时) entry.AbsoluteExpirationRelativeToNow = TimeSpan.FromHours(1); // 并行加载数据 var celulas = await _context.Celulas.Select(c => new { c.Id, c.Nome }).ToListAsync(); var uap = await _context.UAP.Select(u => new { u.Id, u.Nome }).ToListAsync(); var referencias = await _context.Referencias.Select(r => new { r.Id, r.Nome }).ToListAsync(); var celulaTipos = await _context.CelulaTipos.Select(ct => new { ct.Id, ct.Nome }).ToListAsync(); return new { Celulas = celulas, UAP = uap, Referencias = referencias, CelulaTipos = celulaTipos }; }); // 构建SelectList ViewData["CelulaId"] = new SelectList(dropdownData.Celulas, "Id", "Nome"); ViewData["UAPId"] = new SelectList(dropdownData.UAP, "Id", "Nome"); ViewData["ReferenciaId"] = new SelectList(dropdownData.Referencias, "Id", "Nome"); ViewData["CelulaTipoId"] = new SelectList(dropdownData.CelulaTipos, "Id", "Nome"); }
同步版本(不推荐,但如果必须用)
如果因为某些原因不能使用异步方法,至少要先把所有需要的数据加载到内存,同时只选择必要字段:
public void OnGet() { // 先加载所有需要的数据到内存(仍然是4次查询,但只取必要字段) var celulas = _context.Celulas.Select(c => new { c.Id, c.Nome }).ToList(); var uap = _context.UAP.Select(u => new { u.Id, u.Nome }).ToList(); var referencias = _context.Referencias.Select(r => new { r.Id, r.Nome }).ToList(); var celulaTipos = _context.CelulaTipos.Select(ct => new { ct.Id, ct.Nome }).ToList(); // 构建SelectList ViewData["CelulaId"] = new SelectList(celulas, "Id", "Nome"); ViewData["UAPId"] = new SelectList(uap, "Id", "Nome"); ViewData["ReferenciaId"] = new SelectList(referencias, "Id", "Nome"); ViewData["CelulaTipoId"] = new SelectList(celulaTipos, "Id", "Nome"); }
关键优化点总结
- 减少数据传输:用
Select()投影只获取Id和Nome,避免加载实体的其他冗余字段 - 并行加载:通过
Task.WhenAll()让多个查询并行执行,降低总耗时 - 缓存静态数据:对不经常变动的基础数据添加缓存,彻底减少数据库查询次数
内容的提问来源于stack exchange,提问作者Jackal
相关产品推荐
相关产品推荐

