为了账号安全,请及时绑定邮箱和手机立即绑定

实体框架/ Linq EXpression从字符串转换为int

/ 猿问

实体框架/ Linq EXpression从字符串转换为int

喵喵时光机 2019-12-05 16:04:28

我有一个这样的表达式:


var values = Enumerable.Range(1,2);


return message => message.Properties.Any(

    p => p.Key == name 

    && int.Parse(p.Value) >= values[0] 

    && int.Parse(p.Value) <= values[1]);

这样编译可以,但是当它命中数据库时会抛出异常 'LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method, and this method cannot be translated into a store expression '


如果我不进行分析并且将值设置为a string[],则不能在字符串上使用>=and <=运算符。


p.Value 是一个包含各种值的字符串,但是在这种情况下,它是 int


有没有一种方法可以查询数据库以执行这种之间的语句?


查看完整描述

3 回答

?
喵喔喔

正如其他人在评论中指出的那样,您必须解析该值的事实应该是一个危险信号,即您应该在数据库中使用其他数据类型。


幸运的是,有一种解决方法,可以强制查询由LINQ到对象而不是LINQ到实体执行。不幸的是,这意味着潜在地将大量数据读入内存


编辑


根据您的其他评论,“值”列中的值不能保证为数字。因此,您必须尝试将值转换为数字,然后根据该转换的失败/成功来处理事情:


return message

       .Properties

       .AsEnumerable()

       .Any(p => 

            {

                var val = 0;

                if(int.TryParse(p.Value, out val))

                {

                    return p.Key == name &&

                           val >= values[0] &&

                           val <= values[1])

                }

                else

                {

                    return false;

                }

           );

编辑2


您实际上可能能够在数据库中解决这个问题。我不确定这是否对您有用,但您可以试一下:


return message.Properties

              .Where(p => p.Key == name && SqlFunctions.IsNumeric(p.Value) > 0)

              .Any(p => Convert.ToInt32(p.Value) >= values[0] &&

                        Convert.ToInt32(p.Value) <= values[1]);


查看完整回答
反对 回复 2019-12-05
?
幕布斯5086720

尽管我讨厌这个答案,但实际答案是您做起来并不容易。这将是一个真正的痛苦。我见过很多错误的答案,很多人回答说您首先应该只将数据库字段设置为正确的类型,这没有帮助。


您的问题类似于MSDN上的问题。


根据您使用的是哪种EF,有几种可能。


1.您正在使用EDMX文件。

(不是先编写代码,也不是先进行反向工程代码)。


您可以使用类似以下内容(来自此答案):


[EdmFunction("PlusDomain", "ParseDouble")]

public static double ParseDouble(string stringvalue)

{

    // This method exists for use in LINQ queries,

    // as a stub that will be converted to a SQL CAST statement.

    return System.Double.Parse(stringvalue);

}

并将其映射到您的EDMX中,如下所示:


<Function Name="ParseDouble" ReturnType="Edm.Double">

    <Parameter Name="stringvalue" Type="Edm.String" />

    <DefiningExpression>

        cast(stringvalue as Edm.Double)

    </DefiningExpression>

</Function>

2.如果首先在EF> = 4.1中使用代码。

你完了。Microsoft认为不适合在Windows XP中添加任何此类功能SqlFunctions。您最好的期望是在数据库中添加标量SQL函数,并(也许)尝试将其映射到您的上下文中。Microsoft认为首先在代码中执行类似操作没有任何意义。幸运的是,他们也没有完全阻止此类事情。Fluent API功能强大。


您可以像下面这样调用函数或存储过程(参考):


var outParam = new SqlParameter("overHours", SqlDbType.Int);

outParam.Direction = ParameterDirection.Output;

或者像这样(参考):


var data = context.Database.ExecuteSqlCommand("dbo.sp_getNumberJobs @overHours OUT", outParam);

int numJobs = (int)outParam.Value;

但是要使它们真正集成到LINQ to Entities中,您需要使用EntityFramework.CodeFirstStoreFunctions NuGet包,例如CodeFirstFunctions。它将SQL函数映射到上下文中,但是它使用仅针对.NET 4.5的外部库(请参见此处)。


相反,您可以尝试手动执行相同的操作(如此问题)。


根据我的需要,更快的解决方案是仅使用转换后的类型创建视图。这避免了整个问题。


查看完整回答
反对 回复 2019-12-05
?
潇潇雨雨

我最近不得不在LINQ查询中将字符串(数字表示形式)转换为枚举值,而没有实现查询。我的枚举使用0到9之间的int值,所以我最终做了这样的事情:


    .Select(str => (MyEnum?)(SqlFunctions.Unicode(str) - 48))

我知道这不能为问题提供完整的解决方案,但是在像我这样的情况下它肯定可以工作。也许有些人会发现它有用。


查看完整回答
反对 回复 2019-12-05

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信