【问题标题】:Entity Framework/Linq EXpression converting from string to int实体框架/Linq EXpression 从字符串转换为 int
【发布时间】:2015-10-11 03:41:41
【问题描述】:

我有一个这样的表达式:

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[],我就不能在字符串上使用 &gt;=&lt;= 运算符。

p.Value 是一个包含各种值的字符串,但在本例中为int

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

【问题讨论】:

  • 您的Value 在您的数据库中应该是int,这不是一个危险信号吗?
  • 啊,必须喜欢“内部平台效应”...使用数据库表构建数据库表(列/行)...
  • Convert.ToInt32(p.Value) 工作吗?
  • 请改用Convert.ToInt32。 EF 明白这一点。
  • 不行,我试过了

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


【解决方案1】:

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

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

【讨论】:

  • 已经回答here。此外,&gt;= -1 也不正确。
【解决方案2】:

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

您的问题类似于this question on MSDN

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

1。您正在使用 EDMX 文件。

(不是代码优先或逆向工程代码优先)。

你可以使用这样的东西 (from this answer):

[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 认为不适合将任何此类功能添加到 SqlFunctions。您可以期望的最好的方法是将标量 SQL 函数添加到您的数据库中,并(也许)尝试将其映射到您的上下文中。微软认为首先在代码中做这样的事情没有任何意义。幸运的是,他们也没有完全阻止这些事情。 Fluent API 功能强大。

你可以像这样调用函数或存储过程(reference):

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

或者像这样(reference):

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

但要使它们真正集成到 LINQ to Entities 中,您需要使用 CodeFirstFunctions 之类的东西,方法是使用 EntityFramework.CodeFirstStoreFunctions NuGet 包。它将 SQL 函数映射到上下文中,但它使用了一个仅为 .NET 4.5 制作的外部库(请参阅here)。

相反,您可以尝试手动执行相同的操作,例如 this question

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

【讨论】:

  • 我知道这是一个旧答案,但它确实有助于让我了解最近的问题。答案很好,但是还有一种方法可以先用代码使用模型定义的函数!不过,这需要更多的工作。请参阅stackoverflow.com/questions/29503962/… 此外,MS 代码似乎在实际的 C# 代码中抛出 NotImplementedException("not for direct calls"),我认为这是明智的。该调用旨在从表达式树转换为实际 SQL,而不是直接调用!
【解决方案3】:

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

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

我知道这并没有为问题提供完整的解决方案,但它绝对适用于我这样的情况。也许有些人会觉得它很有用。

【讨论】:

    【解决方案4】:

    正如 cmets 中的其他人所指出的,您必须解析此值这一事实应该是一个危险信号,表明您应该在数据库中使用不同的数据类型。

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

    编辑

    根据您的其他 cmets,Value 列中的值不能保证是数字。因此,您必须尝试将值转换为数字,然后根据该转换的失败/成功进行处理:

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

    【讨论】:

    • 我试图不这样做,因为这是过滤方法的一部分,它应该命中数据库并以这种方式返回过滤后的数据
    • @Jon - 由于数据不一定是数字,因此没有很好的方法来处理数据库中的转换。您的选择是使用与上述类似的代码或使用字符串进行比较。
    • 我如何使用大于/小于运算符进行比较的字符串
    • bum,我得到 LINQ to Entities 无法识别方法 'Int32 ToInt32(System.String)' 方法,并且该方法无法转换为存储表达式。
    • 您的第二次编辑在 7 年后挽救了我的生命。谢谢!
    【解决方案5】:

    你可以试试Convert.ToInt32(input);如果你不确定,你可以TryParse。它不会抛出异常,但 false 是无法解析的。但是Convert.ToInt32(input); 应该可以工作。您可以在http://msdn.microsoft.com/en-us/library/vstudio/bb397679.aspx 上阅读。

    【讨论】:

    • 您不能在查询 EF 表达式中使用 TryParse
    • 没有机会马上检查,但谢谢你!认为它可以工作。
    猜你喜欢
    • 2019-01-22
    • 2011-12-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-07
    相关资源
    最近更新 更多