.Net Core LINQ多条件查询:List<int>为空时如何跳过对应筛选逻辑
电商商品多维度动态筛选实现方案
核心实现逻辑
利用IQueryable的延迟执行特性,逐步拼接过滤条件,仅当参数有效(非空/非空集合/非空白字符串)时才追加对应筛选规则,从根源避免空引用异常,同时消除大量重复代码。
完整重构后代码
public async Task<List<Product>> GetProductAllList(ProductFilterQuery productFilterQuery) { // 1. 定义基础查询:所有场景通用的基础过滤规则 var baseQuery = DBContext.Products .Where(x => !x.IsDeleted && x.CompanyID != 0 && x.FileRepos.Count != 0 && x.Company.CompanyIsInShopping && x.ProductIsActive); // 2. 动态追加筛选条件:仅参数有效时才拼接对应规则 if (productFilterQuery.IsFiltered) { // 处理集合类ID筛选 if (productFilterQuery.CategoryIDCollection?.Any() == true) baseQuery = baseQuery.Where(x => productFilterQuery.CategoryIDCollection.Contains(x.CategoryID)); if (productFilterQuery.SubCategoryIDCollection?.Any() == true) baseQuery = baseQuery.Where(x => productFilterQuery.SubCategoryIDCollection.Contains(x.SubCategoryID)); if (productFilterQuery.ChildCategoryIDCollection?.Any() == true) baseQuery = baseQuery.Where(x => productFilterQuery.ChildCategoryIDCollection.Contains(x.ChildCategoryID)); if (productFilterQuery.VariantValueIDCollection?.Any() == true) baseQuery = baseQuery.Where(x => productFilterQuery.VariantValueIDCollection.Contains(x.VariantValueID)); if (productFilterQuery.CategoryVariantIDCollection?.Any() == true) baseQuery = baseQuery.Where(x => productFilterQuery.CategoryVariantIDCollection.Contains(x.CategoryVariantID)); // 处理价格区间筛选 if (productFilterQuery.MinValueOfPrice > 0) baseQuery = baseQuery.Where(x => x.ProductPrice >= productFilterQuery.MinValueOfPrice); if (productFilterQuery.MaxValueOfPrice > productFilterQuery.MinValueOfPrice) baseQuery = baseQuery.Where(x => x.ProductPrice <= productFilterQuery.MaxValueOfPrice); // 处理字符串类型筛选 if (!string.IsNullOrWhiteSpace(productFilterQuery.SearchValue)) baseQuery = baseQuery.Where(x => x.ProductName.Contains(productFilterQuery.SearchValue)); if (!string.IsNullOrWhiteSpace(productFilterQuery.VendorValue)) baseQuery = baseQuery.Where(x => x.ProductVendor.Equals(productFilterQuery.VendorValue)); if (!string.IsNullOrWhiteSpace(productFilterQuery.TagValue)) baseQuery = baseQuery.Where(x => x.ProductTag.Contains(productFilterQuery.TagValue)); } // 3. 统一计算分页参数 const int pageSize = 12; int totalCount = await baseQuery.CountAsync(); int skipCount = pageSize * (productFilterQuery.IndexValue - 1); int takeCount = pageSize; int remainingCount = totalCount - (productFilterQuery.IndexValue * pageSize); if (remainingCount > 0 && remainingCount < pageSize) { takeCount = pageSize + remainingCount; } // 4. 统一执行映射、排序、分页查询 return await baseQuery .Select(x => new Product { ProductID = x.ProductID, DataGuidID = x.DataGuidID, ProductName = x.ProductName, ProductVendor = x.ProductVendor, ProductSecondPhotoID = x.ProductSecondPhotoID, ProductPrice = x.ProductPrice, FileRepos = x.FileRepos.Select(f => new FileRepo { FileData = f.FileData, FileID = f.FileID, FilePhotoIsDefault = f.FilePhotoIsDefault, }).Where(a => a.FilePhotoIsDefault || a.FileID == x.ProductSecondPhotoID).ToList(), CurrencyValue = new CurrencyValue { CurrencyValueData = x.CurrencyValue.CurrencyValueData, Currency = new Currency { CurrencySymbol = x.CurrencyValue.Currency.CurrencySymbol } } }) .OrderBy(x => x.ProductID) .Skip(skipCount) .Take(takeCount) .ToListAsync(); }
方案说明
- 空引用防护:集合参数使用
?.Any() == true判断,参数为null或空集合时自动跳过对应筛选,不会触发空引用异常 - 无冗余代码:原代码中4份重复的查询、映射逻辑统一抽为公共部分,整体代码量减少70%,后续新增筛选条件仅需追加一行判断即可
- 兼容性:EF/EF Core可正常识别链式拼接的Where条件,会自动翻译为最优SQL语句,无性能损耗
- 可扩展性:可将筛选逻辑封装为IQueryable的扩展方法,供其他查询场景复用
内容的提问来源于stack exchange,提问作者BerkGarip
相关产品推荐
相关产品推荐

