Kri*_*tel 5 .net c# linq iqueryable linq-expressions
我已经编写了一些代码来允许在我们的网站上过滤产品,而且我的代码味道非常糟糕.用户可以选择1-*这些过滤器,这意味着我需要特定于该WHERE子句.
我想我正在寻找一种构建lambda表达式的方法,所以对于每个过滤器我都可以"修改"我的WHERE子句 - 但我不确定如何在.NET中执行此操作,并且必须有一种方法.
处于当前状态的代码(实际上是硬编码的,而不是动态的,添加更多过滤器选项会很麻烦).
public static class AgeGroups
{
public static Dictionary<string, int> Items = new Dictionary<string, int>(){
{ "Modern (Less than 10 years old)", 1 },
{ "Retro (10 - 20 years old)", 2 },
{ "Vintage(20 - 70 years old)", 3 },
{ "Antique(70+ years old)", 4 }
};
public static IQueryable<ProductDTO> FilterAgeByGroup(IQueryable<ProductDTO> query, List<string> filters)
{
var values = new List<int>();
var currentYear = DateTime.UtcNow.Year;
foreach (var key in filters)
{
var matchingValue = Items.TryGetValue(key, out int value);
if (matchingValue)
{
values.Add(value);
}
}
if (Utility.EqualsIgnoringOrder(values, new List<int> { 1 }))
{
query = query.Where(x => x.YearManufactured >= currentYear - 10);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 2 }))
{
query = query.Where(x => x.YearManufactured <= currentYear - 10 && x.YearManufactured >= currentYear - 20);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 3 }))
{
query = query.Where(x => x.YearManufactured <= currentYear - 20 && x.YearManufactured >= currentYear - 70);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 4 }))
{
query = query.Where(x => x.YearManufactured <= currentYear - 70);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 1, 2}))
{
query = query.Where(x => x.YearManufactured >= currentYear - 20);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 1, 3 }))
{
query = query.Where(x => x.YearManufactured >= currentYear - 10 || (x.YearManufactured <= currentYear - 20 && x.YearManufactured >= currentYear - 70));
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 1, 4 }))
{
query = query.Where(x => x.YearManufactured >= currentYear - 10 || x.YearManufactured <= currentYear - 70);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 2, 3 }))
{
query = query.Where(x => x.YearManufactured <= currentYear - 10 && x.YearManufactured >= currentYear - 70);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 2, 4 }))
{
query = query.Where(x => (x.YearManufactured <= currentYear - 10 && x.YearManufactured >= currentYear - 20)
|| x.YearManufactured <= currentYear - 70);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 1, 2, 3 }))
{
query = query.Where(x => x.YearManufactured >= currentYear - 70);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 1, 2, 4 }))
{
query = query.Where(x => x.YearManufactured >= currentYear - 20 || x.YearManufactured <= currentYear - 70);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 2, 3, 4}))
{
query = query.Where(x => x.YearManufactured <= currentYear - 10);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 1, 3, 4}))
{
query = query.Where(x => x.YearManufactured >= currentYear - 10 || x.YearManufactured <= 20);
}
else if (Utility.EqualsIgnoringOrder(values, new List<int> { 1, 2, 3, 4 }))
{
// all
}
return query;
}
}
Run Code Online (Sandbox Code Playgroud)
我自己最近也遇到了这个问题。通过另一个问题的帮助,我发现了http://www.albahari.com/nutshell/predicatebuilder.aspx。基本上,您想要构建一个谓词并将其传递到查询的 where 子句中。
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> where1,
Expression<Func<T, bool>> where2)
{
InvocationExpression invocationExpression = Expression.Invoke(where2,
where1.Parameters.Cast<Expression>());
return Expression.Lambda<Func<T, bool>>(Expression.OrElse(where1.Body,
invocationExpression), where1.Parameters);
}
public static IQueryable<ProductDTO> FilterAgeByGroup(IQueryable<ProductDTO> query,
List<string> filters, int currentYear)
{
var values = new HashSet<int>();
//Default value
Expression<Func<ProductDTO, bool>> predicate = (ProductDTO) => false;
foreach (var key in filters)
{
var matchingValue = Items.TryGetValue(key, out int value);
if (matchingValue)
{
values.Add(value);
}
}
if (values.Count == 0)
return query;
if (values.Contains(1))
{
predicate = predicate.Or(x => x.YearManufactured >= currentYear - 10);
}
if (values.Contains(2))
{
predicate = predicate.Or(x => x.YearManufactured <= currentYear - 10 &&
x.YearManufactured >= currentYear - 20);
}
if (values.Contains(3))
{
predicate = predicate.Or(x => x.YearManufactured <= currentYear - 20 &&
x.YearManufactured >= currentYear - 70);
}
if (values.Contains(4))
{
predicate = predicate.Or(x => x.YearManufactured <= currentYear - 70);
}
return query.Where(predicate);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
292 次 |
| 最近记录: |