Linq - 用于查询运算符'Where'使用谓词的不支持的重载

时间:2015-01-15 17:57:07

标签: c# linq linq-to-sql

我正在尝试修复一些性能不佳的Linq查询,但我遇到了Linq语法问题。我比SQL更擅长SQL。

当前工作版本只使用了连接,但这是无效的,因为它返回了多行,然后是DISTINCTed。我想将连接转换为EXISTS子句。当我向Where子句添加谓词时,它几乎可以工作但是会窒息。代码编译但我得到上述错误。关于SO的问题有类似的错误信息,但它们似乎都处理略有不同的情况。

此代码有效:

query = from contact in query
        where Context.TblJobToBrandLink.Join(Context.TblBrandSpends
                                                    //.Where(spendExpression)
                                                    .Where(x => x.IntBrandiD != 0), 
                                             x => x.IntBrandId, 
                                             y => y.IntBrandiD, 
                                             (x, y) => x
                                            ).Any(jobToBrand => jobToBrand.IntJobId == contact.IntJobId)
        select contact;

产生的SQL正是我所期望的。

如果我使用.Where(spendExpression)取消注释该行,则会得到不受支持的重载错误。

spendExpression的类型为Linq.Expressions.Expression< Func< TblBrandSpend,bool>>

它适用于使用连接的版本:

query = from contact in query
        join jobToBrand in Context.TblJobToBrandLink on contact.IntJobId equals jobToBrand.IntJobId
        join brandSpend in Context.TblBrandSpends.Where(spendExpression) on jobToBrand.IntBrandId equals brandSpend.IntBrandiD
        where brandSpend.IntBrandiD != 0
        select contact;

有什么想法吗?

1 个答案:

答案 0 :(得分:3)

我可以在类似的查询表达式中重现这一点。异常的堆栈跟踪如下所示:

  

at System.Data.Linq.SqlClient.QueryConverter.VisitSequenceOperatorCall(MethodCallExpression mc)
  在System.Data.Linq.SqlClient.QueryConverter.VisitMethodCall(MethodCallExpression mc)
  在System.Data.Linq.SqlClient.QueryConverter.VisitInner(表达式节点)
  在System.Data.Linq.SqlClient.QueryConverter.VisitWhere(表达式序列,LambdaExpression谓词)
  ...
  在System.Collections.Generic.List 1..ctor(IEnumerable 1集合)
  在System.Linq.Enumerable.ToList [TSource](IEnumerable`1 source)

因此,LINQ-to-SQL表达式访问者绊倒了一些意想不到的复杂性。这意味着这只是一个错误,你必须解决它。

什么有效(在我的情况下)直接使用表达式:

query = from contact in query
        where Context.TblJobToBrandLink
                     .Join(Context.TblBrandSpends
                     .Where(x => ...) // spendExpression's Expression here
                     ...

或将Context.TblBrandSpends.Where(spendExpression).Where(x => x.IntBrandiD != 0)部分放在查询之外:

var brandSpends = Context.TblBrandSpends
                         .Where(spendExpression)
                         .Where(x => x.IntBrandiD != 0);

query = from contact in query
        where Context.TblJobToBrandLink
                     .Join(brandSpends,
                         x => x.IntBrandId, 
                         y => y.IntBrandiD, 
                         (x, y) => x)
                     .Any(jobToBrand => jobToBrand.IntJobId == contact.IntJobId)
        select contact;

顺便说一句,它适用于实体框架。