C# 是否可以在Lambda表达式中包含SqlFunctions.StringConvert?

C# 是否可以在Lambda表达式中包含SqlFunctions.StringConvert?,c#,entity-framework-4,lambda,expression,C#,Entity Framework 4,Lambda,Expression,我一直在学习表达式,并使用下面的代码根据数据库模型(EF4-ORACLE不是SQL!) 这对Oracle非常有效,并允许我动态地将诸如“CustomerId”、“Contains”、2之类的谓词构建到f=>f.CustomerId.ToString().ToLower().Contains(“2”) 但是,如果我尝试使用SQL Server,那么它会失败,因为我需要调用SqlFunctions.StringConvert——但我不知道如何将其包含在Lambda中 我的最终结果是: f=>

我一直在学习表达式,并使用下面的代码根据数据库模型(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")
Thx:)


编辑:添加了我尝试过的示例

这段代码看起来几乎可以正常工作了
但是,它在
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])'


公共静态表达式AddToString(此表达式)
{
返回表达式.Lambda(
Expression.Call(Expression.Body,
“ToString”,
无效的
空),
表达式(参数);
}
公共静态表达式AddToLower(此表达式)
{
返回表达式.Lambda(
Expression.Call(Expression.Body,
“托洛尔”,
无效的
空),
表达式(参数);
}
公共静态表达式AddContains(此表达式,字符串searchValue)
{
返回表达式.Lambda(
表情,打电话(
表情,身体,
“包含”,
无效的
表达式.常量(searchValue)),
表达式(参数);
}

我认为您基本上需要构建以下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);
        }
    }
}
命名空间控制台应用程序8
{
公共类MyEntity
{
公共int Id{get;set;}
公共整数{get;set;}
}
公共类MyContext:DbContext
{
公共数据库集实体{get;set;}
}
班级计划
{
静态void Main(字符串[]参数)
{
使用(var ctx=new MyContext())
{
如果(!ctx.Entities.Any())
{
Add(newmyentity(){Number=123});
Add(newmyentity(){Number=1893});
Add(newmyentity(){Number=46});
ctx.SaveChanges();
}
foreach(ctx.Entities.Where(e=>SqlFunctions.StringConvert((double?)e.Number.)中的var实体包含(“6”))
{
WriteLine(“{0}{1}”,entity.Id,entity.Number);
}
foreach(ctx.Entities.Where(BuildLambda(“Number”,“6”))中的var实体)
{
WriteLine(“{0}{1}”,entity.Id,entity.Number);
}
}
}
私有静态表达式BuildLambda(字符串propertyName,字符串值)
{
var parameterExpression=Expression.Parameter(typeof(T),“e”);
变量stringConvertMethodInfo=
typeof(SqlFunctions).GetMethod(“StringConvert”,新类型[]{typeof(double?});
var StringContainesMethodInfo=
typeof(String).GetMethod(“包含”);
返回
Lambda(
表情,打电话(
表情,打电话(
stringConvertMethodInfo,
表达式。转换(
Expression.Property(parameterExpression,“Number”),
类型(双?),
StringContainesMethodInfo,
表达式.常量(值)),
参数表达式);
}
}
}

根据异常消息-SqlFunctions.StringConvert()的参数为double?(即,
可空
)而不是双精度类型()。cExp表达式的计算结果为双精度类型的值。您需要创建一个可为null类型的实例(即
新的可为null(表达式)
)的等价物),或者直接强制转换为double?使用Expression.Convert。您甚至可以尝试使用Expression.Convert而不是调用“.ToDouble()”,这让我几乎回到了开始的位置,即EF4的SQL提供程序不支持该方法…因此,我无法调用它:(指定的方法'System.String StringConvert(System.Nullable`1[System.Double])“在类型上”System.Data.Objects.SqlClient.SqlFunctions“无法转换为LINQ to Entities存储表达式。最恼人的是,这适用于Oracle数据库,但不适用于SQL Server数据库。Oracle曾考虑包含“包含”转换-MS没有:(实际上,我认为SqlFunctions中的函数只用于模式匹配。您应该将它们放在树中,以便EF将其正确地转换为相应的存储函数。这就是我遇到的问题:EF无法将Int32(标识列)转换为字符串以执行包含(“xxx”)在它上面。例如,我可以使用
f=>f.Id==2
f=>f.Name.Contains(“Fred”)
但不能使用
f.Id.ToString.Contains(“2”)
。如果我给它一个确切的Id列表,如
IEnumerable({2202})
,那么它返回Id=2+Id=202-但这不是我真正想要的。Name.Contains(“Fred”)大致翻译为
其中的名称,如“%Fred%”
e => SqlFunctions.StringConvert((double?) e.Number).Contains("6"))
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);
        }
    }
}