我正在尝试为IQueryable创建WhereLike扩展,但我无法在运行时知道该属性的类型。
这是我的代码:
def getTasks(database):
print "Checking for new tasks"
query = 'SELECT * FROM fosbot_tasks WHERE asked = %s'
args = (0)
try:
with database.cursor() as cursor:
cursor.execute(query, args)
return cursor.fetchall()
except database.Error as e:
print e
我得到了例外:实例属性' foo'未定义类型' System.Object'
您是否知道在编译时不知道目标类型的情况下处理属性设置的方法?
答案 0 :(得分:1)
如果您能够使用通用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%");
答案 1 :(得分:-1)
确定特定字符串是否与指定模式匹配。模式可以包括常规字符和通配符。在模式匹配期间,常规字符必须与字符串中指定的字符完全匹配。但是,通配符可以与字符串的任意片段匹配。使用通配符使LIKE运算符比使用=和!=字符串比较运算符更灵活。如果任何一个参数不是字符串数据类型,则SQL Server数据库引擎会将其转换为字符串数据类型(如果可能)。 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);