.Net Core linq where with multiple List<int> and string

.Net Core linq where with multiple List<int> and string

我正在尝试为我的电子商务网站进行产品筛选。 我希望我的客户在尝试筛选产品时有多种选择。首先,我想向我的 ProductFilterViewModel 展示;

    public class ProductFilterViewModel
    {
        public List<int> CategoryIDCollection { get; set; }
        public List<int> SubCategoryIDCollection { get; set; }
        public List<int> ChildCategoryIDCollection { get; set; }
        public List<int> VariantValueIDCollection { get; set; }
        public List<int> CategoryVariantIDCollection{ get; set; }
        public int MaxValueOfPrice {get;set;}
        public int MinValueOfPrice {get;set;}
        public string SearchValue { get;set;}
        public string VendorValue { get;set;}
        public string TagValue { get;set;}
        public int IndexValue { get;set;}
        public int PageCount { get;set;}
        public bool IsSearched { get;set;}
        public bool IsFiltered { get;set;}
    }

如您所见,有 14 属性 条关于过滤产品的信息,我想在一次查询中完成所有 Where(x=>x.Value==condition) 条件。例如;

DBContext.Products.Where(x => x.IsDeleted != true && x.CompanyID != 0 &&
  x.FileRepos.Count != 0 && x.Company.CompanyIsInShopping == true && 
  x.ProductIsActive == true && 
  productFilterViewModel.CategoryIDCollection.Contains(x.CategoryID)).ToList();

当我执行该查询并且当 productFilterViewModel.CategoryIDCollection 为空时,它会像往常一样给我一个空异常错误。这就是我要解决的问题。

如果 productFilterViewModel.CategoryIDCollection 列表为空,我希望该查询继续。可能吗 ?如果可能,那么如何?

有一个过滤器 属性,例如 14,如果我用 if like 检查所有内容:if(productFilterViewModel.CategoryIDCollection!=null && ...etc) 这将是一个很长的方法,我将重复自己。 这是我的查询:

 public async Task<List<Product>> GetProductAllList(ProductFilterQuery productFilterQuery)
        {
            if (productFilterQuery.IsFiltered == false) //if there is a no filter 
            {
                int countOfAvailableProduct = DBContext.Products.Where(x => x.IsDeleted != true && x.CompanyID != 0 && x.FileRepos.Count != 0 &&
                    x.Company.CompanyIsInShopping == true && x.ProductIsActive==true).Count();
                int remainingOfProductCount = countOfAvailableProduct - (productFilterQuery.IndexValue * 12);
                if (remainingOfProductCount > 0 && remainingOfProductCount < 12)
                {
                    return await DBContext.Products.Where(x => x.IsDeleted != true && x.CompanyID != 0 && x.FileRepos.Count != 0 &&
                       x.Company.CompanyIsInShopping == true)
                      .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 == true || 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(12 * (productFilterQuery.IndexValue - 1)).Take(12 + remainingOfProductCount).ToListAsync();
                }
                else
                {
                    return await DBContext.Products.Where(x => x.IsDeleted != true && x.CompanyID != 0 && x.FileRepos.Count != 0 &&
                        x.Company.CompanyIsInShopping == true)
                       .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 == true || 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(12 * (productFilterQuery.IndexValue - 1)).Take(12).ToListAsync();
                }
            }
            else // this is the place where i wanna apply those all where conditions
            {
                int countOfAvailableProduct =  DBContext.Products.Where(x => x.IsDeleted != true && x.CompanyID != 0 && x.FileRepos.Count != 0 &&
                                  x.Company.CompanyIsInShopping == true && x.ProductIsActive == true).Count();
                int remainingOfProductCount = countOfAvailableProduct - (productFilterQuery.IndexValue * 12);
                if (remainingOfProductCount > 0 && remainingOfProductCount < 12)
                {
                    return await DBContext.Products.Where(x => x.IsDeleted != true && x.CompanyID != 0 && x.FileRepos.Count != 0 &&
                       x.Company.CompanyIsInShopping == true)
                      .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 == true || 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(12 * (productFilterQuery.IndexValue - 1)).Take(12 + remainingOfProductCount).ToListAsync();
                }
                else
                {
                    return await DBContext.Products.Where(x => x.IsDeleted != true && x.CompanyID != 0 && x.FileRepos.Count != 0 &&
                        x.Company.CompanyIsInShopping == true)
                       .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 == true || 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(12 * (productFilterQuery.IndexValue - 1)).Take(12).ToListAsync();
                }
            }

        }

我正在努力解决这个问题,比如 2 天,所以任何帮助都会非常好。

写你自己的扩展怎么样...像这样(我建议写两个扩展,你会需要的)。

// Queryable
public static class QueryableExtensions
{
    public static IQueryable<TSource> WhereIf<TSource>([NotNull] this IQueryable<TSource> query, bool condition,
        Expression<Func<TSource, bool>> whereExpression) where TSource : class =>
        condition ? query.Where(whereExpression) : query;
}

// Enumerable
public static class EnumerableExtensions
{
    public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> query, bool condition,
        Func<TSource, bool> whereExpression) =>
        condition ? query.Where(whereExpression) : query;
}

然后根据您的条件使用它链接,例如:

DBContext.Products
    .Where(x => !x.IsDeleted && x.CompanyID != 0) // static condition, always get evaluate
    .WhereIf(MinValueOfPrice != 0, x => x.Price > MinValueOfPrice) // Optional condition
    .WhereIf(MaxValueOfPrice != 0, x => x.Price < MaxValueOfPrice) // Optional condition
    ... // Fill your rest condition
    .OrderBy().Skip().Take().ToList(OrArray,... anything you like)

并且为了更好的优化,为您贴图部分

.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 == true || a.FileID == x.ProductSecondPhotoID).ToList(),
                          CurrencyValue = new CurrencyValue
                          {
                              CurrencyValueData = x.CurrencyValue.CurrencyValueData,
                              Currency = new Currency
                              {
                                  CurrencySymbol = x.CurrencyValue.Currency.CurrencySymbol
                              }
                          }
                      })

// Extract the this part As Func<Product, Product> some where like
public static class ManualMappingWrapper
{
    public static Func<Product, Product> ProductProjection = x => new Product() // Fill the rest here
}

// Then reuse it in you query
DbContext.Products.where(something).select(ManualMappingWrapper.ProductProjection);

而且更进一步,我强烈建议给 Automapper 一个机会,它有一个调用 .ProjecTo() 的扩展,这可能会为您节省更多时间。