gpt4 book ai didi

c# - 是否可以将反射与 linq to entity 一起使用?

转载 作者:可可西里 更新时间:2023-11-01 08:40:40 27 4
gpt4 key购买 nike

我试图通过创建一个扩展方法来一般地处理过滤来稍微清理我的代码。

这是我要清理的代码。

var queryResult = (from r in dc.Retailers select r);
if (!string.IsNullOrEmpty(firstName))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(firstName.Trim(), ex.FirstName.Trim()) > 0);
if (!string.IsNullOrEmpty(lastName))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(lastName.Trim(), ex.LastName.Trim()) > 0);
if (!string.IsNullOrEmpty(companyName))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(companyName.Trim(), ex.CompanyName.Trim()) > 0);
if (!string.IsNullOrEmpty(phone))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(phone.Trim(), ex.Phone.Trim()) > 0);
if (!string.IsNullOrEmpty(email))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(email.Trim(), ex.Email.Trim()) > 0);
if (!string.IsNullOrEmpty(city))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(city.Trim(), ex.City.Trim()) > 0);
if (!string.IsNullOrEmpty(zip))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(zip.Trim(), ex.Zip.Trim()) > 0);
if (!string.IsNullOrEmpty(country))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(country.Trim(), ex.Country.Trim()) > 0);
if (!string.IsNullOrEmpty(state))
queryResult = queryResult.Where(ex => SqlFunctions.PatIndex(state.Trim(), ex.State.Trim()) > 0);

这显然非常重复。因此,我尝试创建一个扩展方法,该方法使用反射按属性进行过滤。这是方法。

public static void FilterByValue<T>(this IQueryable<T> obj, string propertyName, string propertyValue)
{
if (!string.IsNullOrEmpty(propertyValue))
{
obj =
obj.Where(
ex =>
SqlFunctions.PatIndex(propertyValue.Trim(), (string)typeof(T).GetProperty(propertyName,
BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase).GetValue(ex)) > 0
);
}
}

它应该这样调用:

var queryResult = (from r in dc.Retailers select r);
queryResult.FilterByValue("firstname", firstName);

但是,当 linq 执行时我得到一个错误,指出“GetValue”在 linq to entity 中不被识别。

那么,有没有其他方法可以清理它,或者我必须让它变得丑陋?

最佳答案

从技术上讲,是的,你可以做到,但你需要构建 Expression自己传递给Where .

也就是说,与其将属性作为字符串值接受,不如考虑接受 Expression<Func<T, string>>。作为参数,这样您就可以在编译时支持验证所选对象是否有效。

我们将从表示通用部分的表达式开始;它将代表一个带有*两个*参数的函数,对象和给定属性的值。然后我们可以用我们在实际方法的参数中定义的属性选择器替换第二个参数的所有实例。

public static IQueryable<T> FilterByValue<T>(
this IQueryable<T> obj,
Expression<Func<T, string>> propertySelector,
string propertyValue)
{
if (!string.IsNullOrEmpty(propertyValue))
{
Expression<Func<T, string, bool>> expression =
(ex, value) => SqlFunctions.PatIndex(propertyValue.Trim(),
value.Trim()) > 0;

var newSelector = propertySelector.Body.Replace(
propertySelector.Parameters[0],
expression.Parameters[0]);

var body = expression.Body.Replace(expression.Parameters[1],
newSelector);
var lambda = Expression.Lambda<Func<T, bool>>(
body, expression.Parameters[0]);

return obj.Where(lambda);
}
else
return obj;
}

并且此方法使用函数将给定表达式中一个表达式的所有实例替换为另一个表达式。它的实现是:

public class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}

public static Expression Replace(this Expression expression,
Expression searchEx, Expression replaceEx)
{
return new ReplaceVisitor(searchEx, replaceEx).Visit(expression);
}

如果您真的想要接受属性名称作为字符串,那么只需替换 newSelector 的定义即可。具有以下内容:

var newSelector = Expression.Property(expression.Parameters[0], propertyName);

关于c# - 是否可以将反射与 linq to entity 一起使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19733364/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com