.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()
的扩展,这可能会为您节省更多时间。
我正在尝试为我的电子商务网站进行产品筛选。
我希望我的客户在尝试筛选产品时有多种选择。首先,我想向我的 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()
的扩展,这可能会为您节省更多时间。