如何用LINQ实现IQueryable多条件过滤及去重取最新Timestamp?
解决LINQ多条件过滤+去重+取最新时间戳的问题
我看了你当前的代码,问题主要出在这几个地方:
- 循环遍历每个版本会触发多次数据库查询,效率很低
GroupBy(x => x.CompanyName).SelectMany(y => y)其实又把分组后的结果拆回了原集合,根本没实现去重逻辑- 完全没处理「保留每个CompanyName对应最新Timestamp记录」的需求,计数也没基于去重后的结果
下面是符合你所有需求的实现方案,用LINQ一步到位完成所有操作:
public List<ReleaseStatistics> GetReleaseStatistics(IQueryable<InstallationInformation> input, IQueryable<DBContext.Version> mapping) { // 1. 关联版本映射和安装信息,一次性过滤出匹配ProductVersion的记录 var filteredData = from info in input join version in mapping on info.ProductVersion equals version.VersionNumber select new { info, version }; // 2. 按「公司名+版本名」分组,每组取Timestamp最新的那条记录 var groupedLatestRecords = filteredData .GroupBy(x => new { x.info.CompanyName, x.version.ReleaseName }) .Select(g => g.OrderByDescending(x => x.info.Timestamp).First()); // 3. 按版本名分组统计去重后的客户数,转换为目标列表 var releaseStats = groupedLatestRecords .GroupBy(x => x.version.ReleaseName) .Select(g => new ReleaseStatistics { ReleaseVersion = g.Key, CustomerCount = g.Count() }) .ToList(); return releaseStats; }
代码逻辑说明:
- 关联过滤:用
join把安装信息和版本映射关联,一次性筛选出所有匹配版本的记录,避免循环多次查询数据库 - 取最新记录:按「公司名+版本名」分组,每组内按Timestamp倒序排列后取第一条,确保每个公司对应版本只保留最新的那条数据
- 统计转换:按版本名分组,统计每组的数量(也就是去重后的客户数),直接转换为
ReleaseStatistics列表返回
如果想进一步优化(避免两次GroupBy),也可以用这种写法:
public List<ReleaseStatistics> GetReleaseStatistics(IQueryable<InstallationInformation> input, IQueryable<DBContext.Version> mapping) { var releaseStats = input .Join(mapping, info => info.ProductVersion, version => version.VersionNumber, (info, version) => new { info, version }) .GroupBy(x => new { x.info.CompanyName, x.version.ReleaseName }) .Select(g => new { ReleaseName = g.Key.ReleaseName, LatestTimestamp = g.Max(x => x.info.Timestamp) }) .GroupBy(x => x.ReleaseName) .Select(g => new ReleaseStatistics { ReleaseVersion = g.Key, CustomerCount = g.Count() }) .ToList(); return releaseStats; }
这两种写法都能满足你的全部需求:版本过滤、CompanyName去重、保留最新Timestamp、统计客户数并返回列表,而且都是基于IQueryable在数据库层面执行查询,性能比你原来的循环写法高效得多。
内容的提问来源于stack exchange,提问作者johhny
相关产品推荐
相关产品推荐

