C# Linq查询上的空检查习惯了吗?
使用Linq to SQL,我想知道以下三种语言中哪一种更惯用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提供程序都可能在应用程
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/实体
,但它们的行为非常不同
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())