Entity framework EF动态查询类

Entity framework EF动态查询类,entity-framework,expression,dynamicquery,Entity Framework,Expression,Dynamicquery,在使用字符串函数“contains”成功地实现了一个like函数之后,我注意到通配符在转换为sql时被转义 当我搜索一条以p开头并有数字13的街道时。我用“%”替换所有空格,但EF将其转义。输出查询如下所示: SELECT " FROM Customer WHERE (LOWER([Street]) LIKE N'%p~%13%' ESCAPE N'~') public static Expression<Func<T, bool>> Create<T>(s

在使用字符串函数“contains”成功地实现了一个like函数之后,我注意到通配符在转换为sql时被转义

当我搜索一条以p开头并有数字13的街道时。我用“%”替换所有空格,但EF将其转义。输出查询如下所示:

SELECT " FROM Customer WHERE (LOWER([Street]) LIKE N'%p~%13%' ESCAPE N'~')
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:
            expressionBody = Expression.Call(GetLowerCasePropertyAccess(memberExpression), ContainsMethod, Expression.Constant(comparedValue1.ToLower()));
            break;
    }

    return Expression.Lambda<Func<T, bool>>(expressionBody, new ParameterExpression[] { parameterExpression });
}

private static MethodCallExpression GetLowerCasePropertyAccess(MemberExpression 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 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;
    else
    {
        var systemType = Nullable.GetUnderlyingType(e.Type) ?? e.Type;
        if (systemType == typeof(int) || systemType == typeof(long) || systemType == typeof(double) || systemType == typeof(short) || systemType == typeof(byte))
        {
            // cast int to double
            var doubleExpr = Expression.Convert(e, typeof(double?));
            strExpression = Expression.Call(StringConvertMethodDouble, doubleExpr);
        }
        else 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 readonly MethodInfo ContainsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
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?) });
在其中一个博客中,有人建议改用patindex。我只是不知道如何实现这一点

我当前的代码如下所示:

SELECT " FROM Customer WHERE (LOWER([Street]) LIKE N'%p~%13%' ESCAPE N'~')
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:
            expressionBody = Expression.Call(GetLowerCasePropertyAccess(memberExpression), ContainsMethod, Expression.Constant(comparedValue1.ToLower()));
            break;
    }

    return Expression.Lambda<Func<T, bool>>(expressionBody, new ParameterExpression[] { parameterExpression });
}

private static MethodCallExpression GetLowerCasePropertyAccess(MemberExpression 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 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;
    else
    {
        var systemType = Nullable.GetUnderlyingType(e.Type) ?? e.Type;
        if (systemType == typeof(int) || systemType == typeof(long) || systemType == typeof(double) || systemType == typeof(short) || systemType == typeof(byte))
        {
            // cast int to double
            var doubleExpr = Expression.Convert(e, typeof(double?));
            strExpression = Expression.Call(StringConvertMethodDouble, doubleExpr);
        }
        else 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 readonly MethodInfo ContainsMethod = typeof(String).GetMethod("Contains", new Type[] { typeof(String) });
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?) });
公共静态表达式创建(字符串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;
开关(比较运算符)
{
...
案例比较运算符。包含:
expressionBody=Expression.Call(GetLowerCasePropertyAccess(memberExpression),ContainsMethod,Expression.Constant(comparedValue1.ToLower());
打破
}
返回表达式.Lambda(expressionBody,新参数表达式[]{ParameterExpression});
}
私有静态方法CallExpression GetLowerCasePropertyAccess(MemberExpression propertyAccess)
{
var stringExpression=GetConvertToString表达式(propertyAccess);
if(stringExpression==null)
抛出新异常(string.Format(“不支持的属性类型{0}”,propertyAccess.type));
返回Expression.Call(stringExpression,typeof(string).GetMethod(“ToLower”,Type.EmptyTypes));
}
私有静态表达式GetConvertToString表达式(表达式e)
{
//如果属性字符串-不需要强制转换
//else-使用SqlFunction.StringConvert(double?)或SqlFunction.StringConvert(decimal?);
表达式strExpression=null;
如果(e.Type==typeof(string))strExpression=e;
其他的
{
var systemType=Nullable.GetUnderlyingType(e.Type)??e.Type;
如果(systemType==typeof(int)| | systemType==typeof(long)| | systemType==typeof(double)| | systemType==typeof(short)| | systemType==typeof(byte))
{
//将int转换为double
var doubleExpr=表达式.Convert(e,typeof(double?);
strExpression=Expression.Call(StringConvertMethodDouble,doubleExpr);
}
else if(systemType==typeof(十进制))
{
//调用StringConvert方法的十进制版本
//强制转换为可为空的十进制数
var decimalExpr=表达式.Convert(e,typeof(decimal?);
strExpression=Expression.Call(StringConvertMethodDecimal,decimalExpr);
}
}
回归表达;
}
私有静态只读方法info ContainsMethod=typeof(String).GetMethod(“Contains”,新类型[]{typeof(String)});
私有静态只读MethodInfo StringConvertMethodDouble=typeof(SqlFunctions).GetMethod(“StringConvert”,新类型[]{typeof(double?});
私有静态只读MethodInfo StringConvertMethodDecimal=typeof(SqlFunctions).GetMethod(“StringConvert”,新类型[]{typeof(decimal?});
像这样:

ctx.Products.Where(x => SqlFunctions.PatIndex("%Something%", x.Name) > 1).ToList();
但这与:

ctx.Products.Where(x => x.Name.Contains("Something")).ToList();

嗨,我需要知道如何构建表达式(在表达式体上方的中)。