简体   繁体   English

LINQ 表达式中的 String.IsNullOrWhiteSpace

[英]String.IsNullOrWhiteSpace in LINQ Expression

I have the following code:我有以下代码:

return this.ObjectContext.BranchCostDetails.Where(
    b => b.TarrifId == tariffId && b.Diameter == diameter
        || (b.TarrifId==tariffId && !string.IsNullOrWhiteSpace(b.Diameter))
        || (!b.TarrifId.HasValue) && b.Diameter==diameter);

And I get this error when I try to run the code:当我尝试运行代码时出现此错误:

LINQ to Entities does not recognize the method 'Boolean IsNullOrWhiteSpace(System.String)' method, and this method cannot be translated into a store expression." LINQ to Entities 无法识别方法 'Boolean IsNullOrWhiteSpace(System.String)' 方法,并且此方法无法转换为存储表达式。”

How can I solve this problem and write code better than this?我怎样才能解决这个问题并写出比这更好的代码?

You need to replace你需要更换

!string.IsNullOrWhiteSpace(b.Diameter)

with

!(b.Diameter == null || b.Diameter.Trim() == string.Empty)

For Linq to Entities this gets translated into:对于 Linq to Entities,这被翻译成:

DECLARE @p0 VarChar(1000) = ''
...
WHERE NOT (([t0].[Diameter] IS NULL) OR (LTRIM(RTRIM([t0].[Diameter])) = @p0))

and for Linq to SQL almost but not quite the same对于 Linq to SQL 几乎但不完全相同

DECLARE @p0 NVarChar(1000) = ''
...
WHERE NOT (LTRIM(RTRIM([t0].[TypeName])) = @p0)

In this case it is important to distinguish between IQueryable<T> and IEnumerable<T> .在这种情况下,区分IQueryable<T>IEnumerable<T>很重要。 In short IQueryable<T> is processed by a LINQ provider to deliver an optimized query.简而言之IQueryable<T>由 LINQ 提供程序处理以提供优化的查询。 During this transformation not all C# statements are supported, as it either is not possible to translate them to a back-end specific query (eg SQL) or because the implementer did not foresee the need for the statement.在此转换期间,并非所有 C# 语句都受支持,因为无法将它们转换为后端特定查询(例如 SQL),或者因为实现者没有预见到需要该语句。

In contrast IEnumerable<T> is executed against the concrete objects and, therefore, will not be transformed.相反, IEnumerable<T>是针对具体对象执行的,因此不会被转换。 So, it is quite common that constructs, which are useable with IEnumerable<T> , cannot be used with IQueryable<T> and also that IQueryables<T> backed by different LINQ providers do not support the same set of functions.因此,可与IEnumerable<T>一起使用的构造不能与IQueryable<T>一起使用,并且由不同 LINQ 提供程序支持的IQueryables<T>不支持同一组函数,这是很常见的。

However, there are some workarounds (like Phil's answer ), which modify the query.但是,有一些变通方法(如Phil 的回答)可以修改查询。 Also, as a more general approach it is possible to drop back to an IEnumerable<T> before continuing with the specification of the query.此外,作为一种更通用的方法,可以在继续查询规范之前回退到IEnumerable<T> This, however, might have a performance hit - especially when using it on restrictions (eg where clauses).然而,这可能会影响性能 - 特别是在限制(例如 where 子句)上使用它时。 In contrast, when dealing with transformations the performance hit is a lot smaller, sometimes even non existent - depending on your query.相比之下,在处理转换时,性能影响要小得多,有时甚至不存在 - 取决于您的查询。

So the above code could also be rewritten like this:所以上面的代码也可以改写成这样:

return this.ObjectContext.BranchCostDetails
    .AsEnumerable()
    .Where(
        b => b.TarrifId == tariffId && b.Diameter == diameter
        || (b.TarrifId==tariffId && !string.IsNullOrWhiteSpace(b.Diameter))
        ||(!b.TarrifId.HasValue) && b.Diameter==diameter
    );

NOTE: Ths code will have an higher performance impact than Phil's answer .注意:此代码将比Phil 的答案具有更高的性能影响。 However, it shows the principle.但是,它显示了原理。

Use an expression visitor to detect references to string.IsNullOrWhiteSpace and break them down into a simpler expression (x == null || x.Trim() == string.Empty) .使用表达式访问者检测对 string.IsNullOrWhiteSpace 的引用并将它们分解为更简单的表达式(x == null || x.Trim() == string.Empty)

So below is an extended visitor and an extension method to make use of it.所以下面是一个扩展的访问者和一个使用它的扩展方法。 It requires no special config to use, simply call WhereEx instead of Where.它不需要特殊的配置来使用,只需调用 WhereEx 而不是 Where。

public class QueryVisitor: ExpressionVisitor
{
    protected override Expression VisitMethodCall(MethodCallExpression node)
    {
        if (node.Method.IsStatic && node.Method.Name == "IsNullOrWhiteSpace" && node.Method.DeclaringType.IsAssignableFrom(typeof(string)))
        {
            //!(b.Diameter == null || b.Diameter.Trim() == string.Empty)
            var arg = node.Arguments[0];
            var argTrim = Expression.Call(arg, typeof (string).GetMethod("Trim", Type.EmptyTypes));

            var exp = Expression.MakeBinary(ExpressionType.Or,
                    Expression.MakeBinary(ExpressionType.Equal, arg, Expression.Constant(null, arg.Type)),
                    Expression.MakeBinary(ExpressionType.Equal, argTrim, Expression.Constant(string.Empty, arg.Type))
                );

            return exp;
        }

        return base.VisitMethodCall(node);
    }
}

public static class EfQueryableExtensions
{
    public static IQueryable<T> WhereEx<T>(this IQueryable<T> queryable, Expression<Func<T, bool>> where)
    {
        var visitor = new QueryVisitor();
        return queryable.Where(visitor.VisitAndConvert(where, "WhereEx"));
    }
}

So if you run myqueryable.WhereEx(c=> !c.Name.IsNullOrWhiteSpace()) it will be converted to !(c.Name == null || x.Trim() == "") before being passes to whatever (linq to sql/entities) and converted to sql.所以如果你运行myqueryable.WhereEx(c=> !c.Name.IsNullOrWhiteSpace())它将被转换为!(c.Name == null || x.Trim() == "")在被传递给任何东西之前(linq to sql/entities) 并转换为 sql。

您还可以使用它来检查空格:

b.Diameter!=null && !String.IsNullOrEmpty(b.Diameter.Trim())
!String.IsNullOrEmpty(b.Diameter.Trim()) 

will throw exception if b.Diameter is null .如果b.Diameternull将抛出异常。
If you still want to use your statement, better use this check如果您仍然想使用您的语句,最好使用此检查

!String.IsNullOrWhiteSpace(b.Diameter), IsNullOrWhiteSpace = IsNullOrEmpty + WhiteSpace

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

相关问题 为什么LINQ无法转换string.IsNullOrWhiteSpace()? - Why can LINQ not translate string.IsNullOrWhiteSpace()? .NET string.IsNullOrWhiteSpace实现 - .NET string.IsNullOrWhiteSpace implementation string.IsNullOrWhiteSpace()和string.IsNullOrEmpty()中的NullReferenceException - NullReferenceException in string.IsNullOrWhiteSpace() and string.IsNullOrEmpty() C#string.IsNullOrWhiteSpace(“\\ t”)== true - C# string.IsNullOrWhiteSpace(“\t”) == true string.IsNullOrEmpty(string)与string.IsNullOrWhiteSpace(string) - string.IsNullOrEmpty(string) vs. string.IsNullOrWhiteSpace(string) string.IsNullOrEmpty &amp; string.IsNullOrWhiteSpace 为空字符串返回 false - string.IsNullOrEmpty & string.IsNullOrWhiteSpace return false for empty string Java等价于c#String.IsNullOrEmpty()和String.IsNullOrWhiteSpace() - Java equivalent of c# String.IsNullOrEmpty() and String.IsNullOrWhiteSpace() .Net 3.5使用代码协定实现String.IsNullOrWhitespace - .Net 3.5 Implementation of String.IsNullOrWhitespace with Code Contracts string.IsNullOrEmpty(myString)或string.IsNullOrWhiteSpace(myString)是否违反了SRP规则? - string.IsNullOrEmpty(myString) or string.IsNullOrWhiteSpace(myString) is not violating SRP Rule? string.IsNullOrEmpty(myString.Trim()) 与 string.IsNullOrWhiteSpace(myString) - string.IsNullOrEmpty(myString.Trim()) vs string.IsNullOrWhiteSpace(myString)
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM