Entity framework 实体框架-动态查询
我正在创建一个动态表达式生成器,并尝试实现“like”函数。在编写我自己的函数之前,我已经搜索了任何现有函数,并找到了一个接近我需要的函数。经过几次实验后,我无法将它用于除字符串以外的其他类型 当我传递类型为Entity framework 实体框架-动态查询,entity-framework,expression,Entity Framework,Expression,我正在创建一个动态表达式生成器,并尝试实现“like”函数。在编写我自己的函数之前,我已经搜索了任何现有函数,并找到了一个接近我需要的函数。经过几次实验后,我无法将它用于除字符串以外的其他类型 当我传递类型为int的参数时,我得到以下错误: 无法使用“System.Int32”类型的实例调用在类型“System.String”上声明的方法“System.String ToString()” 我的代码如下所示: private static MethodCallExpression GetLowe
int
的参数时,我得到以下错误:
无法使用“System.Int32”类型的实例调用在类型“System.String”上声明的方法“System.String ToString()”
我的代码如下所示:
private static MethodCallExpression GetLowerCasePropertyAccess(MemberExpression propertyAccess)
{
//return Expression.Call(Expression.Call(propertyAccess, "ToString", new Type[0]), typeof(string).GetMethod("ToLower", new Type[0]));
return Expression.Call(Expression.Call(propertyAccess, typeof(string).GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
}
private static readonly MethodInfo ContainsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
public static Expression<Func<T, bool>> Create<T>(string propertyName, ComparisonOperators comparisonOperator, dynamic comparedValue1, dynamic comparedValue2 = null)
{
ParameterExpression parameterExpression = Expression.Parameter(typeof(T), "x");
MemberExpression memberExpression = Expression.MakeMemberAccess(parameterExpression, typeof(T).GetProperty(propertyName));
ConstantExpression constantExpression = Expression.Constant(comparedValue1, comparedValue1.GetType());
Expression expressionBody = null;
switch (comparisonOperator)
{
...
case ComparisonOperators.Contains:
//var indexOf = Expression.Call(memberExpression, "IndexOf", null, Expression.Constant(comparedValue1, typeof(string)), Expression.Constant(StringComparison.InvariantCultureIgnoreCase));
//expressionBody = Expression.GreaterThanOrEqual(indexOf, Expression.Constant(0));
expressionBody = Expression.Call(GetLowerCasePropertyAccess(memberExpression), ContainsMethod, Expression.Constant(comparedValue1.ToLower()));
break;
}
return Expression.Lambda<Func<T, bool>>(expressionBody, new ParameterExpression[] { parameterExpression });
}
私有静态方法CallExpression GetLowerCasePropertyAccess(MemberExpression propertyAccess)
{
//返回Expression.Call(Expression.Call(propertyAccess,“ToString”,新类型[0]),typeof(string).GetMethod(“ToLower”,新类型[0]);
返回Expression.Call(Expression.Call(propertyAccess,typeof(string).GetMethod(“ToString”,System.Type.EmptyTypes)),typeof(string).GetMethod(“ToLower”,System.Type.EmptyTypes));
}
私有静态只读方法info ContainsMethod=typeof(String).GetMethod(“Contains”,新类型[]{typeof(String)});
公共静态表达式创建(字符串propertyName、ComparisonOperators、comparisonOperator、dynamic CompariedValue1、dynamic CompariedValue2=null)
{
ParameterExpression ParameterExpression=Expression.Parameter(typeof(T),“x”);
MemberExpression MemberExpression=Expression.MakeMemberAccess(parameterExpression,typeof(T).GetProperty(propertyName));
ConstantExpression ConstantExpression=Expression.Constant(comparedValue1,comparedValue1.GetType());
表达式expressionBody=null;
开关(比较运算符)
{
...
案例比较运算符。包含:
//var indexOf=Expression.Call(memberExpression,“indexOf”,null,Expression.Constant(comparedValue1,typeof(string)),Expression.Constant(StringComparison.invariantCultureInogoreCase));
//expressionBody=Expression.GreaterThanOrEqual(indexOf,Expression.Constant(0));
expressionBody=Expression.Call(GetLowerCasePropertyAccess(memberExpression),ContainsMethod,Expression.Constant(comparedValue1.ToLower());
打破
}
返回表达式.Lambda(expressionBody,新参数表达式[]{ParameterExpression});
}
我不确定我是否完全理解您在做什么,但我认为您的错误是由以下行引起的:
return Expression.Call(Expression.Call(propertyAccess, typeof(string).GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
它将始终尝试为字符串类型调用ToString
方法,因此如果尝试使用Int32
属性,那么您将尝试调用string.ToString()
,因为ToString()的实现
对于不同的类型会有所不同,并且这两种实现不一定兼容,您会看到异常情况:
Method 'System.String ToString()' declared on type 'System.String' cannot be called with instance of type 'System.Int32'
从你所做的事情来看,我认为这可能是你所追求的:
return Expression.Call(Expression.Call(propertyAccess, propertyAccess.Type.GetMethod("ToString", System.Type.EmptyTypes)), typeof(string).GetMethod("ToLower", System.Type.EmptyTypes));
它将使用ToString
(类型从propertyAccess.type
)的正确实现。Linq to entities不支持.ToString
方法。要将数值转换为字符串,需要使用SqlFunctions.StringConvert
方法。我已经修复了您的代码,现在您可以对字符串和数字列执行类似的:
private static Expression GetConvertToStringExpression(Expression e)
{
// if property string - no cast needed
// else - use SqlFunction.StringConvert(double?) or SqlFunction.StringConvert(decimal?);
Expression strExpression = null;
if (e.Type == typeof(string))
strExpression = e;
var systemType = Nullable.GetUnderlyingType(e.Type) ?? e.Type;
if (systemType == typeof(int)
|| systemType == typeof(long)
|| systemType == typeof(double)
|| systemType == typeof(short)
|| systemType == typeof(byte)) // continue
{
// cast int to double
var doubleExpr = Expression.Convert(e, typeof (double?));
strExpression = Expression.Call(StringConvertMethodDouble, doubleExpr);
}
if (systemType == typeof (decimal))
{
// call decimal version of StringConvert method
// cast to nullable decimal
var decimalExpr = Expression.Convert(e, typeof (decimal?));
strExpression = Expression.Call(StringConvertMethodDecimal, decimalExpr);
}
return strExpression;
}
private static MethodCallExpression GetLowerCasePropertyAccess(Expression propertyAccess)
{
var stringExpression = GetConvertToStringExpression(propertyAccess);
if (stringExpression == null)
throw new Exception(string.Format("Not supported property type {0}", propertyAccess.Type));
return Expression.Call(stringExpression,
typeof (string).GetMethod("ToLower", Type.EmptyTypes));
}
private static readonly MethodInfo StringConvertMethodDouble = typeof (SqlFunctions).GetMethod("StringConvert",
new Type[] {typeof (double?)});
private static readonly MethodInfo StringConvertMethodDecimal = typeof(SqlFunctions).GetMethod("StringConvert",
new Type[] { typeof(decimal?) });
我刚刚做了这样的东西:
public Expression<Func<T,bool>> BuildContainsExpression<T>(MemberExpression memberExp, object comparedValue)
{
var parameter = Expression.Parameter(memberExp.Member.DeclaringType, "x");
var method = typeof(string).GetMethod("Contains", types: new[] { typeof(string) });
var comparison = Expression.Equal(
Expression.Call(
method: method,
instance: memberExp,
arguments: Expression.Constant(comparedValue)),
Expression.Constant(true)
);
return Expression.Lambda<Func<T, bool>>(comparison, parameter);
}
public Expression BuildContainsExpression(MemberExpression memberExp,object comparedValue)
{
var参数=Expression.parameter(memberExp.Member.DeclaringType,“x”);
var method=typeof(string).GetMethod(“包含”,类型:new[]{typeof(string)});
变量比较=表达式。相等(
表情,打电话(
方法:方法,,
实例:memberExp,
参数:Expression.Constant(comparedValue)),
表达式.常量(true)
);
返回表达式.Lambda(比较,参数);
}
它构建了一个表达式,如下所示:
x.Language.Contains(“tr”)
(使用我的动态参数)
我尝试了您的解决方案,但现在出现了一个新错误:System.NotSupportedException:LINQ to Entities无法识别“System.String ToString()”方法,此方法无法转换为存储表达式。您好,很抱歉,我必须删除标记答案。我在测试时仍然会出错。不知何故,函数“GetConvertToString Expression”仍然不起作用。我得到的错误是:“int没有ToLower的定义”