具有未知 属性 类型的 IQueryable WhereLike 扩展
IQueryable WhereLike extension with unknown property type
我正在尝试为 IQueryable 创建一个 WhereLike 扩展,但我无法在运行时知道 属性 的类型。
这是我的代码:
public static IQueryable WhereLike(this IQueryable source, string propertyName, string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(typeof(object), "a");
var prop = Expression.Property(a, propertyName);
return source.Provider.CreateQuery(
Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern)));
}
我得到异常:实例 属性 'foo' 没有为类型 'System.Object'
定义
你知道在编译时不知道目标类型的情况下处理 属性 设置的方法吗?
Determines whether a specific character string matches a specified pattern. A pattern can include regular characters and wildcard characters. During pattern matching, regular characters must exactly match the characters specified in the character string. However, wildcard characters can be matched with arbitrary fragments of the character string. Using wildcard characters makes the LIKE operator more flexible than using the = and != string comparison operators. If any one of the arguments is not of character string data type, the SQL Server Database Engine converts it to character string data type, if it is possible. MSDN
Like 运算符仅适用于 string
类型。如果那是你想做的,你可以只用 Contains
方法实现,还有 StartsWith
和 EndsWith
等价物。
您只能在此扩展方法中使用 Where 方法
var containsParam = Expression.Parameter(typeof(T), "p");
MemberExpression multiSelectmember = Expression.Property(containsParam,propertyname);
var lstValues = stringvalue;
ConstantExpression multiSelectConstant = Expression.Constant(stringvalue);
var callExpression = Expression.Call(typeof(String), "Contains",
new[] { typeof(string) }, multiSelectConstant, multiSelectmember);
var containsexp = Expression.Lambda<Func<T, bool>>(callExpression,
containsParam);
如果您能够使用通用 IQueryable<T>
变体,这将变得更容易解决问题,因为您不再需要 CreateQuery
并且可以直接针对 IQueryable<T>
源代码执行。
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, string propertyName,
string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(typeof(T), "a");
var prop = Expression.PropertyOrField(a, propertyName);
var expr = Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern));
var lambda = Expression.Lambda<Func<T, bool>>(expr, a);
return source.Where(lambda);
}
注意两个重点:
如果我们使用 PropertyOrField 而不是仅获取属性,我们可以正确支持为 Linq-2-SQL 生成的可能公开字段的代码。
此外,由于我们是针对 IQueryable<T>
源代码执行的,因此我们需要根据 "Like" MethodCallExpression
.
的结果创建一个 lambda 表达式
如果您需要非通用变体,您仍然可以完成同样的事情,尽管您需要将您的 Like MethodCallExpression
包装在 Where MethodCallExpression
中才能使其成为结构合理:
public static IQueryable WhereLike(this IQueryable source, string propertyName,
string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(source.GetType().GetGenericArguments().First(), "a");
var prop = Expression.PropertyOrField(a, propertyName);
var expr = Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern));
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { source.ElementType },
source.Expression,
Expression.Lambda(expr, a));
return source.Provider.CreateQuery(whereCallExpression);
}
您可以使用通配符调用任一变体:
var data = source.WhereLike("ColumnName", "%o%");
我正在尝试为 IQueryable 创建一个 WhereLike 扩展,但我无法在运行时知道 属性 的类型。
这是我的代码:
public static IQueryable WhereLike(this IQueryable source, string propertyName, string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(typeof(object), "a");
var prop = Expression.Property(a, propertyName);
return source.Provider.CreateQuery(
Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern)));
}
我得到异常:实例 属性 'foo' 没有为类型 'System.Object'
定义你知道在编译时不知道目标类型的情况下处理 属性 设置的方法吗?
Determines whether a specific character string matches a specified pattern. A pattern can include regular characters and wildcard characters. During pattern matching, regular characters must exactly match the characters specified in the character string. However, wildcard characters can be matched with arbitrary fragments of the character string. Using wildcard characters makes the LIKE operator more flexible than using the = and != string comparison operators. If any one of the arguments is not of character string data type, the SQL Server Database Engine converts it to character string data type, if it is possible. MSDN
Like 运算符仅适用于 string
类型。如果那是你想做的,你可以只用 Contains
方法实现,还有 StartsWith
和 EndsWith
等价物。
您只能在此扩展方法中使用 Where 方法
var containsParam = Expression.Parameter(typeof(T), "p");
MemberExpression multiSelectmember = Expression.Property(containsParam,propertyname);
var lstValues = stringvalue;
ConstantExpression multiSelectConstant = Expression.Constant(stringvalue);
var callExpression = Expression.Call(typeof(String), "Contains",
new[] { typeof(string) }, multiSelectConstant, multiSelectmember);
var containsexp = Expression.Lambda<Func<T, bool>>(callExpression,
containsParam);
如果您能够使用通用 IQueryable<T>
变体,这将变得更容易解决问题,因为您不再需要 CreateQuery
并且可以直接针对 IQueryable<T>
源代码执行。
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, string propertyName,
string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(typeof(T), "a");
var prop = Expression.PropertyOrField(a, propertyName);
var expr = Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern));
var lambda = Expression.Lambda<Func<T, bool>>(expr, a);
return source.Where(lambda);
}
注意两个重点:
如果我们使用 PropertyOrField 而不是仅获取属性,我们可以正确支持为 Linq-2-SQL 生成的可能公开字段的代码。
此外,由于我们是针对 IQueryable<T>
源代码执行的,因此我们需要根据 "Like" MethodCallExpression
.
如果您需要非通用变体,您仍然可以完成同样的事情,尽管您需要将您的 Like MethodCallExpression
包装在 Where MethodCallExpression
中才能使其成为结构合理:
public static IQueryable WhereLike(this IQueryable source, string propertyName,
string pattern)
{
if (source == null) throw new ArgumentNullException("source");
if (propertyName == null) throw new ArgumentNullException("propertyName");
var a = Expression.Parameter(source.GetType().GetGenericArguments().First(), "a");
var prop = Expression.PropertyOrField(a, propertyName);
var expr = Expression.Call(
typeof(SqlMethods), "Like",
null,
prop, Expression.Constant(pattern));
MethodCallExpression whereCallExpression = Expression.Call(
typeof(Queryable),
"Where",
new Type[] { source.ElementType },
source.Expression,
Expression.Lambda(expr, a));
return source.Provider.CreateQuery(whereCallExpression);
}
您可以使用通配符调用任一变体:
var data = source.WhereLike("ColumnName", "%o%");