我如何重构此 Lambda 中的 "Property to Use" 以使其可重用?
How can I Refactor This To Pass in the "Property to Use" in this Lambda to Make This Method Reusable?
在我的网页中,有多个文本框供用户输入复杂的查询。一个复杂的查询可以包含以下任何 Parameter
s:
XX*
匹配 以 XX 开头的所有内容
*XX
所有 结尾为 XX
*XX*
所有内容 包含 XX
XX123-XX129
匹配从 XX123 到 XX129 的 包含范围
XX444
精确的个人价值
- ...以上any/all的任何逗号分隔组合
实施这不是我的问题;我的问题是以 可重用 方式为多个值实现它。
下面的示例在 Item.Value
属性 上过滤 Items
。
public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
IEnumerable<Parameter> itemValues)
{
var parameters = (itemValues ?? Enumerable.Empty<Parameter>()).ToList();
if (parameters.IsEmpty()) return items;
var (wildCards, exactMatches) = parameters.SplitOnWildCards();
var predicate = PredicateBuilder.New<Item>(); // https://github.com/scottksmith95/LINQKit
wildCards.ForEach(wc =>
{
switch (wc)
{
case WildCardStartsWith startsWith:
predicate = predicate.Or(s => s.Value.ToUpper().StartsWith(startsWith.ToString()));
break;
case WildCardContains contains:
predicate = predicate.Or(s => s.Value.ToUpper().Contains(contains.ToString()));
break;
case WildCardEndsWith endsWith:
predicate = predicate.Or(s => s.Value.ToUpper().EndsWith(endsWith.ToString()));
break;
}
});
if (exactMatches.Any())
predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(s.Value.ToUpper()));
return items.AsExpandableEFCore().Where(predicate);
}
我如何重构它以便我可以 "pass in" 将 Item.Value
传递给该方法,这样我也可以传入 Item.PartNumber
或 Item.Foo
而不必复制所有我要过滤的每个 属性 的代码?我不能只传入 Item.Value
...那只是一个字符串,在 lambda 语句中不起作用。
编写您的方法以获取表示字段引用的 ExpressionLambda
:
public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
IEnumerable<Parameter> itemValues,
Expression<Func<Item,string>> field)
然后在需要引用字段的代码中,使用LINQKit的Invoke
方法:
case WildCardStartsWith startsWith:
predicate = predicate.Or(s => field.Invoke(s).ToUpper().StartsWith(startsWith.ToString()));
最后,使用 LINQKit 的 Expand
方法内联扩展 field
引用,或者像在数据源上那样使用 AsExpandable
:
if (exactMatches.Any())
predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(field.Invoke(s).ToUpper()));
return items.AsExpandableEFCore().Where(predicate);
在我的网页中,有多个文本框供用户输入复杂的查询。一个复杂的查询可以包含以下任何 Parameter
s:
XX*
匹配 以 XX 开头的所有内容
*XX
所有 结尾为 XX*XX*
所有内容 包含 XXXX123-XX129
匹配从 XX123 到 XX129 的 包含范围
XX444
精确的个人价值- ...以上any/all的任何逗号分隔组合
实施这不是我的问题;我的问题是以 可重用 方式为多个值实现它。
下面的示例在 Item.Value
属性 上过滤 Items
。
public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
IEnumerable<Parameter> itemValues)
{
var parameters = (itemValues ?? Enumerable.Empty<Parameter>()).ToList();
if (parameters.IsEmpty()) return items;
var (wildCards, exactMatches) = parameters.SplitOnWildCards();
var predicate = PredicateBuilder.New<Item>(); // https://github.com/scottksmith95/LINQKit
wildCards.ForEach(wc =>
{
switch (wc)
{
case WildCardStartsWith startsWith:
predicate = predicate.Or(s => s.Value.ToUpper().StartsWith(startsWith.ToString()));
break;
case WildCardContains contains:
predicate = predicate.Or(s => s.Value.ToUpper().Contains(contains.ToString()));
break;
case WildCardEndsWith endsWith:
predicate = predicate.Or(s => s.Value.ToUpper().EndsWith(endsWith.ToString()));
break;
}
});
if (exactMatches.Any())
predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(s.Value.ToUpper()));
return items.AsExpandableEFCore().Where(predicate);
}
我如何重构它以便我可以 "pass in" 将 Item.Value
传递给该方法,这样我也可以传入 Item.PartNumber
或 Item.Foo
而不必复制所有我要过滤的每个 属性 的代码?我不能只传入 Item.Value
...那只是一个字符串,在 lambda 语句中不起作用。
编写您的方法以获取表示字段引用的 ExpressionLambda
:
public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
IEnumerable<Parameter> itemValues,
Expression<Func<Item,string>> field)
然后在需要引用字段的代码中,使用LINQKit的Invoke
方法:
case WildCardStartsWith startsWith:
predicate = predicate.Or(s => field.Invoke(s).ToUpper().StartsWith(startsWith.ToString()));
最后,使用 LINQKit 的 Expand
方法内联扩展 field
引用,或者像在数据源上那样使用 AsExpandable
:
if (exactMatches.Any())
predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(field.Invoke(s).ToUpper()));
return items.AsExpandableEFCore().Where(predicate);