文字列関数 'contains' を使用して like 関数を正常に実装した後、SQL に変換するときにワイルドカードがエスケープされることに気付きました。
例えば。p で始まる通りを検索し、その中に 13 番があるとします。すべてのスペースを「%」に置き換えますが、EF はそれをエスケープします。出力クエリは次のようになります。
SELECT " FROM Customer WHERE (LOWER([Street]) LIKE N'%p~%13%' ESCAPE N'~')
ブログの 1 つで、代わりに 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?) });