EF Dynamic Query - лайк

После успешной реализации подобной функции с использованием строковой функции 'hass' я заметил, что подстановочные знаки экранируются при переводе в sql.

Например. Когда я ищу улицу, начинающуюся с p и имеющую номер 13. Я заменяю все пространство на "%", но EF избегает его. Выходной запрос выглядит следующим образом:

SELECT " FROM Customer WHERE (LOWER([Street]) LIKE N'%p~%13%' ESCAPE N'~')

В одном из блогов было предложено использовать вместо этого patindex. Я просто не знаю, как это реализовать.

Мой текущий код выглядит так:

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?) });

1 ответ

Как это:

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

Но это будет идентично:

ctx.Products.Where(x => x.Name.Contains("Something")).ToList();
Другие вопросы по тегам