Linq IQueryable.Any()用法

Joe*_*ang 4 linq linq-to-entities linq-to-sql

以下是我的代码.请检讨一下.

 1. bool isUnavailable = db.Deploys.Where(p => 
     p.HostEnvironmentId == Guid.Parse(host.ID) &&
     p.Status == (int)DeployStatus.Deploying).AsEnumerable().Any();
Run Code Online (Sandbox Code Playgroud)

这个工作.

以下陈述不起作用.

2. bool isUnavailable = db.Deploys.Where(p => 
    p.HostEnvironmentId == Guid.Parse(host.ID) &&
    p.Status == (int)DeployStatus.Deploying).Any();//Error 
Run Code Online (Sandbox Code Playgroud)

例外是

    An exception of type 'System.NotSupportedException' occurred in 
Microsoft.Data.Services.Client.DLL but was not handled in user code

    Additional information: The method 'Any' is not supported.


3. bool isUnavailable = db.Deploys.Where(p => 
        p.HostEnvironmentId.ToString() == host.ID &&
        p.Status == (int)DeployStatus.Deploying).AsEnumerable().Any();//Error
Run Code Online (Sandbox Code Playgroud)

例外是

    An exception of type 'System.NotSupportedException' occurred in 
      Microsoft.Data.Services.Client.DLL but was not handled in user code
      Additional information: The expression (([10007].HostEnvironmentId.ToString() == 
"b7db845b-cec4-49af-8f4b-b419a4e44331") And ([10007].Status == 90)) is not supported.
Run Code Online (Sandbox Code Playgroud)

Deploys班是这是建立在客户端代理类WCF数据服务的模式.我使用"添加服务引用"来创建WCF客户端代理类.

但至于通用列表,请在下面的代码中提供.它会工作正常.

4.bool b=servers.Where(d => 
   d.status == (int)Enums.ServerStatus.Deploying ||
   d.status == int)Enums.ServerStatus.Unavailable).Any();
Run Code Online (Sandbox Code Playgroud)

我的问题是

为什么在不同类中使用相同的方法得到不同的结果.(参见方法2和方法4).

为什么2和3不起作用.

希望可以有人帮帮我 .谢谢

All*_*nek 5

LINQ有一个"提供者"的概念.在不同数据源上使用LINQ时,根据数据源,相同的LINQ查询需要进行不同的操作.

例如,当您想使用LINQ查询数据库时,需要将LINQ查询转换为SQL查询.当数据源是OData时,需要将查询转换为URL.每个提供程序都有不同的提供程序,每个提供程序都支持LINQ运算符和其他语言结构的不同子集.LINQ-to-SQL,实体框架和LINQ-to-NHibernate是三种流行的数据库访问LINQ提供程序.

在您的情况下,您正在使用WCF数据服务,其中包括OData的LINQ提供程序.由于在OData中无法表达.Any()LINQ运算符,因此尝试在具有该提供程序的查询中使用它会引发异常.通过使用.AsEnumerable()你实际上是说在那时停止使用OData LINQ提供程序并开始使用LINQ-to-Objects提供程序(在技术上不是提供程序,但从概念上讲,你可以将其视为一个提供程序).这意味着只有之前的内容.AsEnumerable()才会被转换为OData查询,从而导致检索Deploy匹配的所有实体.Where(),并且在它们全部转移到客户端之后,客户端将.Any()通过检查Deploy它已收到的实体数量来执行.如果有很多这样的实体,这当然是不好的,当你想要的只是服务器端(可能是数据库)检查是否有任何这样的实体时,它将导致通过网络进行不必要的数据传输.不幸的是,.Any()OData 1.0不支持(我不知道OData 2.0).

此外,OData也可能不支持.ToString().您可能需要Guid直接比较结构,即创建一个包含要比较的GUID值的局部变量:

var g = Guid.Parse("b7db845b-cec4-49af-8f4b-b419a4e44331")`
Run Code Online (Sandbox Code Playgroud)

然后在查询中比较GUID,如下所示:

x.HostedEnvironment == g
Run Code Online (Sandbox Code Playgroud)

  • 为了优化这一点(Allon Guralnek如上所述的数据传输问题):使用.FirstOrDefault()!= null而不是Any.在语义上它做同样的事情,并且OData LINQ提供程序支持FirstOrDefault(翻译为$ top = 1,所以如果有的话,你只会下载第一个实体). (3认同)