【问题标题】:Why isn't this short circuit is not working in linq to sql query?为什么这种短路在 linq to sql 查询中不起作用?
【发布时间】:2018-09-14 16:19:04
【问题描述】:

查询:

List<int> companyIds = null;

(from car in context.GetTable<Car>()
where companyIds == null || companyIds.Contains(car.companyID)
select car)
.ToList();

结果:

在 System.Linq.Enumerable.OfType[TResult](IEnumerable 源) 在 System.Data.Linq.SqlClient.QueryConverter.VisitContains(表达式序列,表达式值) 在 System.Data.Linq.SqlClient.QueryConverter.VisitInner(表达式节点) 在 System.Data.Linq.SqlClient.QueryConverter.VisitExpression(表达式 exp) 在 System.Data.Linq.SqlClient.QueryConverter.VisitBinary(BinaryExpression b) 在 System.Data.Linq.SqlClient.QueryConverter.VisitInner(表达式节点) 在 System.Data.Linq.SqlClient.QueryConverter.VisitExpression(表达式 exp) 在 System.Data.Linq.SqlClient.QueryConverter.VisitWhere(表达式序列,LambdaExpression 谓词) 在 System.Data.Linq.SqlClient.QueryConverter.VisitInner(表达式节点) 在 System.Data.Linq.SqlClient.QueryConverter.ConvertOuter(表达式节点) 在 System.Data.Linq.SqlClient.SqlProvider.BuildQuery(表达式查询,SqlNodeAnnotations 注释) 在 System.Data.Linq.SqlClient.SqlProvider.System.Data.Linq.Provider.IProvider.Execute(表达式查询) 在 System.Data.Linq.DataQuery1.System.Collections.Generic.IEnumerable<T>.GetEnumerator() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 源) 在 EVaultSDK.Services.CompanyService.Get...

如果我添加 ToList

 context.GetTable<Car>().ToList()

有效

【问题讨论】:

  • 问号运算符在这里适用吗?
  • @maccettura 不确定我是否同意,上面提供的代码在逻辑上是正确的,尽管它缺少 select 所以我不确定它是否完整。
  • @maccettura,读一下短路,如果第一条是真的,不需要执行第二条
  • @cosset 您可以尝试在此处添加ToListcontext.GetTable&lt;Car&gt;().ToList() 并查看是否再次遇到异常。你能发布异常的完整堆栈跟踪吗?
  • @CetinBasoz,是的,你的答案可以称为解决方案,但它在逻辑上是不正确的,如果我传递给方法空(非空)companyIds,我希望该方法不返回任何内容,因为这个目的 companyIds 可以是可以为空,

标签: c# linq linq-to-sql


【解决方案1】:

我认为原因是您使用的是 LINQ to SQL,您的查询需要被转换为 SQL,而在发生这种转换时您会遇到异常。 Contains 在 SQL 中被翻译成 IN 运算符。但由于列表为空,我认为 LINQ to SQL 提供程序会引发异常。

这就是为什么在GetTable&lt;Car&gt;() 之后添加ToList 时不会出现异常的原因,这会导致您在内存中获取并加载所有Cars,因此查询在内存上运行所以不要需要翻译成 SQL 并且短路按预期工作。

通常,如果您在空列表上调用Contains,您应该得到NullReferenceException,但您得到的是ArgumentNullException。因此,您应该检查堆栈跟踪,如果是这种情况,请不要在查询中使用空列表。

编辑:您发布的堆栈跟踪证实了我的假设。在路上的某个地方,OfType 方法在列表中被调用,它会导致异常。

【讨论】:

    【解决方案2】:

    您已经很好地回答了为什么会出现错误 - 并非 C# 中的所有内容都可以很好地转换为 SQL,而且您通常直到运行时才发现。

    以防万一未来的访问者遇到此问题以寻找解决方法, 我建议使用这样一个事实,即您可以构建一个查询,并且在您调用ToList()(或Single(),等等......)之前它不会检索任何数据:

    List<int> companyIds = null;
    
    var query = context.GetTable<Car>();
    if (companyIds != null)
        query = query.Where(car => companyIds.Contains(car.companyID));
    
    var result = query.ToList();
    

    【讨论】:

    • 嘿,准备好因为提供解决方案而不是回答他的问题而被否决:) 顺便说一句,你错过了 AsQueryable()。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-26
    • 2018-01-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多