简体   繁体   English

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

[英]Entity Framework/Linq EXpression converting from string to int

I have an Expression like so:我有一个像这样的表达式:

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

This compiles fine but when it hits the database it throws the exception 'LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method, and this method cannot be translated into a store expression '这编译得很好,但是当它访问数据库时,它会抛出异常'LINQ to Entities does not recognize the method 'Int32 Parse(System.String)' method, and this method cannot be translated into a store expression '

If I don't do the parse and have values be a string[] I can't then use the >= and <= operators on strings.如果我不进行解析并且值为string[]我就不能在字符串上使用>=<=运算符。

p.Value is a string which holds various values but in this case it is int p.Value是一个包含各种值的字符串,但在这种情况下它是int

Is there a way I can query the database to do this sort of between statement?有没有办法可以查询数据库以在语句之间执行此类操作?

As much as I hate this answer, the actual answer is you can't do it easily.尽管我讨厌这个答案,但实际的答案是你不能轻易做到。 It will be a real pain.这将是一个真正的痛苦。 I've seen lots of wrong answers and lots of answers with people saying you should just have your database fields be the correct type in the first place, which is not helpful.我看到很多错误的答案,很多人说你应该首先让你的数据库字段是正确的类型,这没有帮助。

Your question is similar to this question on MSDN .您的问题类似于MSDN上的这个问题

There are several possibilities depending on what sort of EF you are using.根据您使用的 EF 类型,有多种可能性。

1. You are using EDMX files. 1. 您正在使用 EDMX 文件。

(Not code first or reverse engineered code first). (不是代码优先或逆向工程代码优先)。

You can use something like this ( 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);
}

and map it in your EDMX like this:并将其映射到您的 EDMX 中,如下所示:

<Function Name="ParseDouble" ReturnType="Edm.Double">
    <Parameter Name="stringvalue" Type="Edm.String" />
    <DefiningExpression>
        cast(stringvalue as Edm.Double)
    </DefiningExpression>
</Function>

2. If you are using code first in EF >= 4.1. 2. 如果您在 EF >= 4.1 中首先使用代码。

You are screwed.你完了。 Microsoft didn't see fit to add any such function to SqlFunctions . Microsoft 认为不适合将任何此类功能添加到SqlFunctions The best you can hope for is to add a scalar SQL function into your database and (maybe) try to map it into your context.您所能希望的最好结果是将一个标量 SQL 函数添加到您的数据库中,并且(也许)尝试将其映射到您的上下文中。 Microsoft didn't see any point in doing anything like this in code first.微软认为首先在代码中做这样的事情没有任何意义。 Fortunately they didn't totally block such things either.幸运的是,他们也没有完全阻止这些事情。 The Fluent API is powerful. Fluent API 功能强大。

You can call the functions or stored procedures like this ( reference ):您可以像这样调用函数或存储过程( 参考):

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

Or like this ( reference ):或者像这样( 参考):

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

But to make them actually integrate into LINQ to Entities, you need something like CodeFirstFunctions , by using the EntityFramework.CodeFirstStoreFunctions NuGet package.但是要使它们真正集成到 LINQ to Entities 中,您需要使用EntityFramework.CodeFirstStoreFunctions NuGet 包,像CodeFirstFunctions这样的东西。 It maps the SQL functions into the context, but it uses an external library only made for .NET 4.5 (see here ).它将 SQL 函数映射到上下文中,但它使用了一个仅适用于 .NET 4.5 的外部库(请参阅此处)。

Instead, you can attempt to do the same thing manually like in this question .相反,您可以尝试像在此问题中那样手动执行相同的操作。

The quicker solution I've settled on for my needs is to just create a view with the converted types.我已经为我的需要确定的更快的解决方案是只创建一个具有转换类型的视图。 This avoids the whole problem.这避免了整个问题。

As pointed out by others in the comments, the fact that you're having to parse this value should be a red flag that you should be using a different data type in your database.正如其他人在评论中指出的那样,您必须解析此值这一事实应该是一个危险信号,表明您应该在数据库中使用不同的数据类型。

Fortunately, there is a workaround by forcing the query to be executed by LINQ to Objects rather than LINQ to Entities.幸运的是,有一种解决方法是强制查询由 LINQ to Objects 而不是 LINQ to Entities 执行。 Unfortunately, it means potentially reading a large amount of data into memory不幸的是,这意味着可能会将大量数据读入内存

EDIT编辑

Based on your other comments, the value in the Value column ins't guaranteed to be a number.根据您的其他评论,“值”列中的值不能保证是数字。 Therefore, you'll have to try converting the value to a number and then handling things based on the failure/success of that conversion:因此,您必须尝试将值转换为数字,然后根据转换的失败/成功进行处理:

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

EDIT 2编辑 2

You might actually be able to get away with this in the database.您实际上可能能够在数据库中摆脱这一点。 I'm not sure if this will work or not for you but give it a shot:我不确定这对你是否有用,但试一试:

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

I recently had to convert a string (numeric representation) to an enumeration value in a LINQ query, without materializing the query.我最近不得不在 LINQ 查询中将字符串(数字表示)转换为枚举值,而没有具体化查询。 My enumeration used int values between 0 and 9, so I ended up doing something like this:我的枚举使用了 0 到 9 之间的 int 值,所以我最终做了这样的事情:

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

I know this is not providing a full solution for the problem, but it definitely works in a situation like mine.我知道这并没有为问题提供完整的解决方案,但它绝对适用于我这样的情况。 Maybe some will find it useful.也许有些人会发现它很有用。

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

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

You can try Convert.ToInt32(input);你可以试试Convert.ToInt32(input); If you are not sure, you can TryParse .如果您不确定,可以TryParse It will not throw exception but false is cannot Parse.它不会抛出异常,但 false 是无法解析的。 But Convert.ToInt32(input);但是Convert.ToInt32(input); should work.应该管用。 You can read about it on http://msdn.microsoft.com/en-us/library/vstudio/bb397679.aspx .您可以在http://msdn.microsoft.com/en-us/library/vstudio/bb397679.aspx上阅读它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM