【问题标题】:Is it possible to include SqlFunctions.StringConvert in a Lambda Expression?是否可以在 Lambda 表达式中包含 SqlFunctions.StringConvert?
【发布时间】:2012-11-27 05:34:52
【问题描述】:

我一直在学习表达式并使用下面的代码来添加针对数据库模型的表达式(EF4 - ORACLE 而不是 SQL!)

这对 Oracle 非常有效,并允许我将 "CustomerId", "Contains", 2 等谓词动态构建到 f=>f.CustomerId.ToString().ToLower().Contains("2")

但是,如果我尝试使用 SQL Server,它会失败,因为我需要调用 SqlFunctions.StringConvert - 但我不知道如何将它包含在 Lambda 中?

我的最终结果会是这样的:

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

【问题讨论】:

  • 根据异常消息- SqlFunctions.StringConvert() 采用双精度参数? (即Nullable&lt;double&gt;)而不是双类型(msdn.microsoft.com/en-us/library/dd487127.aspx)。您的 cExp 表达式的计算结果为 double 类型的值。您需要创建一个可为空类型的实例(即等效于new Nullable&lt;double&gt;(expression))还是只强制转换为双精度?使用 Expression.Convert。您甚至可以尝试使用 Expression.Convert 而不是调用“.ToDouble()”
  • 这让我几乎回到了我开始的地方,即 EF4 的 SQL 提供程序不支持该方法...因此,我不能调用它:( 指定的方法 'System.String StringConvert(System 'System.Data.Objects.SqlClient.SqlFunctions' 类型上的 .Nullable`1[System.Double])' 无法转换为 LINQ to Entities 存储表达式。
  • 最烦人的是,这适用于 Oracle DB,但不适用于 SQL Server。 Oracle 曾考虑包含“包含”翻译 - MS 没有:(
  • 其实我认为SqlFunctions中的函数只是为了模式匹配。您应该将它们放在树中,以便 EF 将其正确转换为相应的存储函数。
  • 这就是我遇到的问题:EF 无法将 Int32(标识列)转换为字符串以对其执行 Contains("xxx")。例如我可以使用f=&gt;f.Id==2f=&gt;f.Name.Contains("Fred"),但不能使用f=&gt;f.Id.ToString.Contains("2")。如果我给它一个确切的 ID 列表作为IEnumerable&lt;int&gt;({2, 202}),包含 DOES 工作,在这种情况下它返回 ID=2 + ID=202 - 但这不是我真正想要的。 Name.Contains("Fred") 大致翻译为Where Name like '%Fred%'

标签: c# entity-framework-4 lambda expression


【解决方案1】:

我相信你基本上需要构建以下 lambda 表达式的等效表达式:

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

这是一个完整的复制粘贴示例。它使用 CodeFirst,因此无需创建数据库或类似的东西就可以工作。只需添加实体框架 nuget 包(我使用的是 EF6,但它也应该适用于 EF5)。构建 lambda 是您真正追求的。

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

【讨论】:

    猜你喜欢
    • 2021-08-27
    • 2017-04-19
    • 2014-09-12
    • 1970-01-01
    • 1970-01-01
    • 2014-06-21
    • 2011-03-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多