[英]Entity Framework/Linq EXpression converting from string to int
我有一个像这样的表达式:
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
有没有办法可以查询数据库以在语句之间执行此类操作?
尽管我讨厌这个答案,但实际的答案是你不能轻易做到。 这将是一个真正的痛苦。 我看到很多错误的答案,很多人说你应该首先让你的数据库字段是正确的类型,这没有帮助。
根据您使用的 EF 类型,有多种可能性。
(不是代码优先或逆向工程代码优先)。
你可以使用这样的东西( 来自这个答案):
[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>
你完了。 Microsoft 认为不适合将任何此类功能添加到SqlFunctions
。 您所能希望的最好结果是将一个标量 SQL 函数添加到您的数据库中,并且(也许)尝试将其映射到您的上下文中。 微软认为首先在代码中做这样的事情没有任何意义。 幸运的是,他们也没有完全阻止这些事情。 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 的外部库(请参阅此处)。
相反,您可以尝试像在此问题中那样手动执行相同的操作。
我已经为我的需要确定的更快的解决方案是只创建一个具有转换类型的视图。 这避免了整个问题。
正如其他人在评论中指出的那样,您必须解析此值这一事实应该是一个危险信号,表明您应该在数据库中使用不同的数据类型。
幸运的是,有一种解决方法是强制查询由 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]);
我最近不得不在 LINQ 查询中将字符串(数字表示)转换为枚举值,而没有具体化查询。 我的枚举使用了 0 到 9 之间的 int 值,所以我最终做了这样的事情:
.Select(str => (MyEnum?)(SqlFunctions.Unicode(str) - 48))
我知道这并没有为问题提供完整的解决方案,但它绝对适用于我这样的情况。 也许有些人会发现它很有用。
您可以使用 SqlFunctions.IsNumeric() 方法,例如,将其存储到列表中。
var resultsArray = context.TableData_DB.Where(x => SqlFunctions.IsNumeric(x.stringField) >= -1).ToList();
你可以试试Convert.ToInt32(input);
如果您不确定,可以TryParse
。 它不会抛出异常,但 false 是无法解析的。 但是Convert.ToInt32(input);
应该管用。 您可以在http://msdn.microsoft.com/en-us/library/vstudio/bb397679.aspx上阅读它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.