3

私は式を学習しており、以下のコードを使用して、データベース モデルに対する式を追加します (EF4 - SQL ではなく ORACLE!)。

これはOracleに対して完全に機能し、次のような述語を動的に構築でき"CustomerId", "Contains", 2ますf=>f.CustomerId.ToString().ToLower().Contains("2")

ただし、SQL Server に対して試行すると、呼び出す必要があるため失敗しますが、それをSqlFunctions.StringConvertLambda に含める方法がわかりません。

私の最終結果は次のようになります。

f=> SqlFunctions.StringConvert(f.CustomerId).ToLower().Contains("2")

どうも :)


編集:私が試したことの例を追加しました

このコードは、ほとんど機能しているように見えます。
ただし、var sqlExpression行にエラーがスローされます

Expression of type 'System.Double' cannot be used for parameter of type 'System.Nullable`1[System.Double]' of method 'System.String StringConvert(System.Nullable`1[System.Double])'


MethodInfo convertDouble = typeof(Convert).GetMethod("ToDouble",new Type[]{typeof(int)});
                    var cExp = Expression.Call(convertDouble, left.Body);

                    var entityParam = Expression.Parameter(typeof(TModel), "f");
                    MethodInfo sqlFunc = typeof(SqlFunctions).GetMethod("StringConvert", new Type[] { typeof(double) });
                    var sqlExpression = Expression.Call(sqlFunc, cExp);


                    MethodInfo contains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
                    right = Expression.Constant(value.ToString(), typeof(string));

                    var result = left.AddToString().AddToLower().AddContains(value.ToString());
                    return result;

public static Expression<Func<T, string>> AddToString<T, U>(this Expression<Func<T, U>> expression)
        {

            return Expression.Lambda<Func<T, string>>(
                Expression.Call(expression.Body,
                "ToString",
                null,
                null),
                expression.Parameters);
        }

        public static Expression<Func<T, string>> AddToLower<T>(this Expression<Func<T, string>> expression)
        {

            return Expression.Lambda<Func<T, string>>(
                Expression.Call(expression.Body,
                "ToLower",
                null,
                null),
                expression.Parameters);
        }

        public static Expression<Func<T, bool>> AddContains<T>(this Expression<Func<T, string>> expression, string searchValue)
        {
            return Expression.Lambda<Func<T, bool>>(
                Expression.Call(
                    expression.Body,
                    "Contains",
                    null,
                    Expression.Constant(searchValue)),
                expression.Parameters);
        }
4

1 に答える 1

5

基本的に、次のラムダ式と同等の式を作成する必要があると思います。

e => SqlFunctions.StringConvert((double?) e.Number).Contains("6"))

以下は完全なコピー&ペーストの例です。CodeFirst を使用しているため、データベースなどを作成しなくても機能するはずです。Entity Framework nuget パッケージを追加するだけです (EF6 を使用しましたが、EF5 でも機能するはずです)。ビルドラムダは、あなたが本当に求めているものです。

namespace ConsoleApplication8
{
    public class MyEntity
    {
        public int Id { get; set; }
        public int Number { get; set; }
    }


    public class MyContext : DbContext
    {
        public DbSet<MyEntity> Entities { get; set; }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (var ctx = new MyContext())
            {
                if (!ctx.Entities.Any())
                {
                    ctx.Entities.Add(new MyEntity() {Number = 123});
                    ctx.Entities.Add(new MyEntity() {Number = 1893});
                    ctx.Entities.Add(new MyEntity() {Number = 46});
                    ctx.SaveChanges();
                }

                foreach(var entity in ctx.Entities.Where(e => SqlFunctions.StringConvert((double?) e.Number).Contains("6")))
                {
                    Console.WriteLine("{0} {1}", entity.Id, entity.Number);
                }

                foreach (var entity in ctx.Entities.Where(BuildLambda<MyEntity>("Number", "6")))
                {
                    Console.WriteLine("{0} {1}", entity.Id, entity.Number);
                }

            }
        }

        private static Expression<Func<T, bool>> BuildLambda<T>(string propertyName, string value)
        {
            var parameterExpression = Expression.Parameter(typeof(T), "e");

            var stringConvertMethodInfo = 
                typeof(SqlFunctions).GetMethod("StringConvert", new Type[] {typeof (double?)});

            var stringContainsMethodInfo =
                typeof (String).GetMethod("Contains");

            return 
                Expression.Lambda<Func<T, bool>>(
                Expression.Call(
                    Expression.Call(
                        stringConvertMethodInfo,
                        Expression.Convert(
                            Expression.Property(parameterExpression, "Number"),
                            typeof (double?))),
                    stringContainsMethodInfo,
                    Expression.Constant(value)),
                parameterExpression);
        }
    }
}
于 2012-11-27T23:18:36.377 に答える