如何在ASPX页面存储查询并复用?ListView查询优化咨询
嘿,针对你的两个ASPX技术问题,我整理了实用的解决方案,看看对你有没有帮助:
1. 在ASPX页面中存储并复用查询的几种方案
这里有几个接地气的思路,你可以根据自己的场景来选:
- 后台预加载+内存缓存:如果查询结果不会频繁变动,在页面首次加载(
Page_Load)的时候,一次性把查询结果拉到内存里,存在后台的私有变量里。如果需要跨页面回发还能拿到数据,就把它存到ViewState或者Session里,后续用的时候直接取变量就行,不用再碰数据库。举个例子:
之后不管是后台逻辑还是前端绑定,直接用private List<ExampleTable> _cachedData; protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // 一次性把数据查出来存到内存 _cachedData = db.ExampleTable.ToList(); // 要是需要回发后还能用,就存到ViewState里 ViewState["CachedExampleData"] = _cachedData; } else { // 回发时从ViewState里取回来 _cachedData = ViewState["CachedExampleData"] as List<ExampleTable>; } }_cachedData就好。 - 用ASP.NET全局缓存(Cache):如果这个查询结果是多个页面共享的,或者需要缓存较长时间,就用
HttpContext.Current.Cache来存,还能设置过期时间,彻底避免重复查询的开销。 - 前端隐藏控件存小数据(不推荐大量数据):如果只是少量的查询结果,可以塞到
<asp:HiddenField>里,但这种方式只适合数据量极小的情况,不然会拖慢页面加载速度。
2. 优化ListView中调用后台函数的数据库查询
你现在的写法有个大问题:ListView每渲染一行,就会触发一次数据库查询,要是列表有几百行,那数据库就得被调用几百次,性能肯定拉胯。完全可以改成提前把所有需要的数据一次性加载到内存,然后直接从内存里取数,把N次查询变成1次,性能提升特别明显。
具体优化步骤:
- 提前拉取所有需要的统计数据:在页面加载的时候,先把ListView要展示的数据源拿出来,然后一次性查询所有
Ids对应的计数,存到一个字典里(键是Ids,值是对应的计数),这样后续查数直接从字典里拿就行。 - 修改后台函数,从字典取数:把原来查数据库的逻辑改成查内存字典,彻底告别重复查询。
优化后的代码示例:
C#后台代码:
// 用字典缓存每个Ids对应的计数,查找速度贼快 private Dictionary<int, int> _idCountDict; protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // 第一步:先获取ListView要绑定的数据源,转成List加载到内存 var membersData = db.ExampleTable.ToList(); lvMembers.DataSource = membersData; lvMembers.DataBind(); // 第二步:一次性查询所有需要的计数,转成字典 // 先把所有需要统计的Ids提取出来 var allIds = membersData.Select(m => m.Ids).ToList(); // 一次查询搞定所有统计,用GroupBy来分组计数 var countQuery = db.ExampleTable .Where(et => allIds.Contains(et.id)) .GroupBy(et => et.id) .Select(g => new { Id = g.Key, Count = g.Count() }); // 转成字典,方便后续快速查找 _idCountDict = countQuery.ToDictionary(item => item.Id, item => item.Count); } } // 修改后的函数,直接从字典里取数,不用碰数据库了 public int CalculateFromDatabase(int Ids) { // 字典里有就返回计数,没有就返回0 return _idCountDict.TryGetValue(Ids, out int count) ? count : 0; }
额外提醒:
- 如果你的ListView有分页、筛选这类动态操作,记得在数据源变化的时候,重新生成这个字典,不然数据会不一致。
- 用Entity Framework的话,
ToList()一定要加,不然会触发延迟执行,还是会多次查数据库。
更简洁的进阶思路:
其实你这个场景还可以更进一步,直接把统计数据和ListView的数据源封装到同一个ViewModel里,这样前端绑定的时候直接用属性,连后台函数都不用调用了。比如:
// 先定义一个ViewModel,把需要展示的字段和统计数据放一起 public class MemberViewModel { public int Ids { get; set; } public int Count { get; set; } } // 页面加载时直接构建ViewModel集合 protected void Page_Load(object sender, EventArgs e) { if (!IsPostBack) { // 一次查询就把所有需要的数据都搞定,不用分开查 var memberViewModels = db.ExampleTable .GroupBy(et => et.Ids) .Select(g => new MemberViewModel { Ids = g.Key, Count = g.Count() }) .ToList(); lvMembers.DataSource = memberViewModels; lvMembers.DataBind(); } }
然后ASPX里直接绑定ViewModel的Count属性就行:
<ItemTemplate> <tr> <td> <%# Item.Count %> </td> </tr> </ItemTemplate>
这种方式代码更简洁,性能也最优,推荐优先考虑。
内容的提问来源于stack exchange,提问作者Milo Khoo
相关产品推荐
相关产品推荐

