Как вызвать sql скалярную функцию в дереве выражений linq с возможностью запроса? - PullRequest
2 голосов
/ 15 апреля 2019

Я создаю лямбда-выражение для Iqueryable, чтобы получить значение из коллекции, но я хочу преобразовать это значение в другой тип данных, например, int или decimal.Так как я не могу использовать приведение c # с Iqueryable, я создал пользовательскую скалярную функцию в sql и пытаюсь получить к ней доступ в выражении, но возникает исключение, что «methodname» не может быть преобразовано в выражение sql.

public class Context
{

[DbFunction("dbo", "ConvertToDouble")]
        public int? ConvertToDouble(string value)
        {
            var sql = $"set @result = dbo.[ConvertToDouble]('{value}')";
            var output = new SqlParameter { ParameterName = @"result", DbType = DbType.Int32, Size = 16, Direction = ParameterDirection.Output };
            var result = Database.ExecuteSqlCommand(sql, output);
            return output.Value as int?;
        }
}


private static Expression<Func<TSource, TDataType>> CreateLamdaExpression<TSource, TDataType>(string fieldName)
        {
            var parameterExpression = Expression.Parameter(typeof(TSource));

            var collectionParameter = Expression.Property(parameterExpression, "CustomFieldValues");
            var childType = collectionParameter.Type.GetGenericArguments()[0];
            var propertyParameter = Expression.Parameter(childType, childType.Name);

            var left = Expression.Property(propertyParameter, "Name");
            var right = Expression.Constant(fieldName);

            var innerLambda = Expression.Equal(left, right);

            var innerFunction = Expression.Lambda(innerLambda, propertyParameter);

            var method = typeof(Enumerable).GetMethods().Where(m => m.Name == "FirstOrDefault" && m.GetParameters().Length == 2).FirstOrDefault().MakeGenericMethod(typeof(CustomFieldValue));

            var outerLambda = Expression.Call(method, Expression.Property(parameterExpression, collectionParameter.Member as System.Reflection.PropertyInfo), innerFunction);
            var propertyGetter = Expression.Property(outerLambda, "Value");

            if (typeof(TDataType) != typeof(object))
            {
               /var changeTypeCall = Expression.Call(Expression.Constant(Context), Context.GetType().GetMethod("ConvertToDouble", BindingFlags.Public | BindingFlags.Instance),
                                                            propertyGetter
                                                               );

                Expression convert = Expression.Convert(changeTypeCall,
                                                        typeof(TDataType));

                return Expression.Lambda<Func<TSource, TDataType>>(convert, new ParameterExpression[] { parameterExpression });
            }

            var result = Expression.Lambda<Func<TSource, TDataType>>(propertyGetter, new ParameterExpression[] { parameterExpression });
            return result;
        }
...