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

时间:2013-05-22 14:39:09

标签: c# .net linq entity-framework entity-framework-4

我有一个像这样的表达式:

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 '

如果我不进行解析并且值为string[],则我无法在字符串上使用>=<=运算符。

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

有没有办法可以查询数据库来进行这种语句?

5 个答案:

答案 0 :(得分:14)

尽管我讨厌这个答案。实际的答案是你不能轻易做到。这将是一个真正的痛苦。 我看到很多错误的答案和许多答案,人们说你应该首先让你的数据库字段成为正确的类型。没用。

此问题与http://social.msdn.microsoft.com/Forums/en-US/ce9652e3-5450-44c4-a9bd-586b4c4e6a27/convert-string-to-int-in-whereorderby-is-it-possible?forum=adodotnetentityframework

类似

根据您使用的EF类型,有几种可能性。

1。您正在使用EDMX文件。

(首先不代码第一个或反向工程代码)。您可以使用类似(LINQ to Entities does not recognize the method 'Double Parse(System.String)' method, and this method cannot be translated into a store expression

的内容
 [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&gt; = 4.1。

中首先使用代码 你被搞砸了。微软认为不适合在SqlFunctions中添加任何此类功能。您可以期待的最好的方法是在您的数据库中添加标量SQL函数,并(可能)尝试将其映射到您的上下文中。微软在代码中首先做了类似的事情没有任何意义。幸运的是,他们也没有完全阻止这样的事情。 Fluent API非常强大。

这将是这样的:

您可以像这样调用函数或存储过程: define scalar function with ef4.1 code first? 要么 http://weblogs.asp.net/dwahlin/using-entity-framework-code-first-with-stored-procedures-that-have-output-parameters 像:

  

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中,你需要更像这样的东西:

https://codefirstfunctions.codeplex.com/ 使用http://www.nuget.org/packages/EntityFramework.CodeFirstStoreFunctions 它将SQL函数映射到上下文中,但它使用仅为.NET 4.5制作的外部库 http://blog.3d-logic.com/2014/04/09/support-for-store-functions-tvfs-and-stored-procs-in-entity-framework-6-1/

或 您可以尝试使用以下内容手动执行相同的操作:

Entity Framework 6 Code First function mapping

https://entityframework.codeplex.com/discussions/494365

或者我为我的需求找到的更快的解决方案是创建一个包含转换类型的视图。这避免了整个问题。

答案 1 :(得分:4)

正如其他人在评论中指出的那样,您必须解析此值的事实应该是一个红色标记,您应该在数据库中使用不同的数据类型。

幸运的是,有一种解决方法是强制查询由LINQ to Objects而不是LINQ to Entities执行。不幸的是,这意味着可能会将大量数据读入内存

修改

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

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

答案 2 :(得分:1)

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

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

我知道这不是为问题提供完整的解决方案,但它肯定适用于我的情况。也许有些人会发现它很有用。

答案 3 :(得分:0)

您可以使用 SqlFunctions.IsNumeric() 方法,例如,将其存储到列表中。

var resultsArray = context.TableData_DB.Where(x => SqlFunctions.IsNumeric(x.stringField) >= -1).ToList();

答案 4 :(得分:-3)

您可以尝试Convert.ToInt32(input);如果您不确定,可以TryParse。它不会抛出异常但是false不能抛出。但Convert.ToInt32(input);应该有用。您可以在http://msdn.microsoft.com/en-us/library/vstudio/bb397679.aspx上阅读相关内容。