C# Linq查询上的空检查习惯了吗?

C# Linq查询上的空检查习惯了吗?,c#,sql,linq,linq-to-sql,C#,Sql,Linq,Linq To Sql,使用Linq to SQL,我想知道以下三种语言中哪一种更惯用 foos.Where(foo=>foo.Bar.HasValue&&foo.Bar.Valuefoo.Bar.Valuefoo.Barfoo.Bar)(由于此处未进行隐式转换,因此会导致类型错误) 人们是否应该努力编写通用查询,使其在最初设计的环境之外使用时不会失败?基础数据存储技术多年来一直在变化。代码似乎比任何人想象的都活得长。我不会对底层存储提供商进行假设 如果Linq是您的抽象层,那么假设任何Linq提供程序都可能在应用程

使用Linq to SQL,我想知道以下三种语言中哪一种更惯用

  • foos.Where(foo=>foo.Bar.HasValue&&foo.Bar.Value<42)
  • foos.Where(foo=>foo.Bar.Value<42)
  • foos.Where(foo=>foo.Bar<42)
第一个选项生成一个额外的
条不为NULL
谓词,该谓词在大多数DBMS中可能正在进行优化。如果查询对象而不是数据库,则必须执行null检查,但由于可以创建在对象上可能失败但在数据库上可能失败的通用
iQuery
查询,因此第一个选项始终有效,尽管Linq和SQL代码都比第二个选项略长。提供的第三个选项似乎是两全其美的,但在
foo.Bar
具有bool类型的情况下不起作用:
foos.Where(foo=>foo.Bar)
(由于此处未进行隐式转换,因此会导致类型错误)


人们是否应该努力编写通用查询,使其在最初设计的环境之外使用时不会失败?

基础数据存储技术多年来一直在变化。代码似乎比任何人想象的都活得长。我不会对底层存储提供商进行假设

如果Linq是您的抽象层,那么假设任何Linq提供程序都可能在应用程序生命周期的某个点插入

前者生成一个额外的Bar IS NOT NULL谓词,该谓词可能在大多数DBMS中被优化掉


我不是一名数据库性能专家,但我认为与许多查询的总体成本相比,额外的“不为空”的性能成本将很小。

我将针对您使用的提供程序编写查询<代码>Linq到对象可能看起来类似于
Linq到sql/实体
,但它们的行为非常不同

  • 它们不支持相同的功能
  • 它们不返回相同的类型
  • 它们的执行方式不同
  • 如果您的linq提供程序将来发生更改,您很可能必须重写查询。例如,有些特定于提供程序的类仅适用于给定的提供程序。您无法预测未来的提供商将支持什么或它将如何工作

    linq to实体中的简单分组查询

    var query = from f in foos
                group f by new { f.Name, f.Bar.Value } into g
                select ...
    

    将导致一个与对象截然不同的查询。尝试找到同时满足这两个条件的查询是否有益?

    第三种选择是使用“提升的”
    Linq到SQL转换器将负责输出正确的SQL。在本例中,伪ORM代码反映了可为空的Bar列。在处理返回的结果时,这在应用程序代码中很有用,但在MS SQL查询的
    where
    子句中就没有这么多了。我将把它留给您的第二选择。

    同意-从数据服务层返回结果时,我不使用Linq枚举,我使用的是XCan列表,您展示了提升的
    @Aducci的一个示例实现:编译器根据
    foos
    @Aducci的编译时类型将lambda表达式视为一个或另一个,它是lambda,而lambda是C#中极少数上下文相关的表达式之一(也就是说,该表达式的编译方式及其含义取决于该表达式的使用方式)。如果
    foos
    是一个
    IEnumerable
    ,则
    可枚举。其中
    将期望
    Func
    作为第一个参数,这意味着lambda将被编译为该委托类型。如果
    foos
    是一个
    IQueryable
    ,则它将调用
    可查询。其中
    期望
    表达式
    ,因此lambda将被编译成一个封装该委托类型的表达式。@Aducci因此,如果
    foo.Bar
    的类型是
    bool?
    并且您希望将null视为false,则这反过来决定编译器是否试图将该代码编译成指向包含调用
    的方法的委托,t当您可以编写
    foos.Where(foo=>foo.Bar.GetValueOrDefault())
    时。要将null视为true,请将
    true
    作为参数传递给GetValueOrDefault。
    foos.Where(foo => foo.Bar < 42)
    
    foo.Bar.GetValueOrDefault() < 42 && foo.Bar.HasValue
    
    foo.Bar < (int?)42
    
    foos.Where(foo => foo.Bar == true)
    
    foos.Where(foo => foo.Bar.GetValueOrDefault())