consultas - linq to dataset samples c#
¿La verificación nula de las consultas de Linq es idiomática? (4)
El traductor Linq-to-SQL será responsable de generar el SQL correcto. En este caso, su pseudo código ORM refleja la columna Bar que admite nulos. Esto es útil en el código de su aplicación, cuando se trabaja con resultados devueltos, pero no tanto para la cláusula where
de una consulta MS SQL según su ejemplo. Lo dejaría en tu segunda opción.
Usando Linq-to-SQL, me pregunto cuál es más idiomático de los siguientes tres ,
foos.Where(foo => foo.Bar.HasValue && foo.Bar.Value < 42)
-
foos.Where(foo => foo.Bar.Value < 42)
-
foos.Where(foo => foo.Bar < 42)
La primera opción genera un predicado adicional de Bar IS NOT NULL
que probablemente se está optimizando en la mayoría de los DBMS. Si se consultan objetos en lugar de una base de datos, la verificación nula sería obligatoria, pero dado que se pueden crear consultas IQueriable<Foo>
genéricas que pueden fallar en objetos pero no en bases de datos, la primera opción siempre funcionaría, aunque tanto Linq como El código SQL es un poco más largo que la segunda opción. La tercera opción, proporcionada por Michael Liu , parece ser la mejor de ambos mundos, pero no funcionará en el caso foo.Bar
tiene tipo bool? : foos.Where(foo => foo.Bar)
(provoca un error de tipo ya que la conversión implícita no se realiza aquí).
¿Debería uno esforzarse por escribir consultas genéricas que no fallarán si se usan fuera del contexto para el que fueron diseñadas originalmente?
Escribiría las consultas específicas para el proveedor que está utilizando. Linq-to-objects
puede parecer similar a linq-to-sql/entities
, pero se comportan de manera muy diferente.
- No son compatibles con las mismas funciones
- No devuelven el mismo tipo
- Se ejecutan de manera diferente
Si su proveedor de linq cambia en el futuro, lo más probable es que tenga que volver a escribir sus consultas de todos modos. Por ejemplo, hay clases específicas del proveedor como SqlFunctions que solo funcionan en el proveedor dado. No puede predecir lo que el futuro proveedor apoyará o cómo funcionará.
Un grupo simple por consulta en linq-a-entidades
var query = from f in foos
group f by new { f.Name, f.Bar.Value } into g
select ...
linq-to-objects
consulta de linq-to-objects
muy diferente. ¿Es beneficioso intentar encontrar una consulta que satisfaga a ambos?
La tecnología de almacenamiento de datos subyacente tiene una forma de cambiar a lo largo de los años. El código parece vivir mucho más tiempo de lo que nadie pensó que lo haría alguna vez. No construiría suposiciones sobre el proveedor de almacenamiento subyacente.
Si Linq es su capa de abstracción, suponga que cualquier proveedor de Linq podría estar conectado en algún momento del ciclo de vida de la aplicación.
El primero genera un predicado adicional de Bar IS NOT NULL que probablemente se está optimizando en la mayoría de los DBMS.
No soy un experto en rendimiento de bases de datos, pero creo que el costo de rendimiento para el IS NOT NULL extra será pequeño en comparación con el costo general de muchas consultas.
Una tercera opción es usar el operador "levantado" <
, que devuelve falso si cualquiera de los operandos es nulo. Esto le permite omitir la comprobación explícita de nulo y funciona para todos los proveedores de LINQ:
foos.Where(foo => foo.Bar < 42)
Si el tipo de foos
tiempo de foos
es IEnumerable<Foo>
, entonces foo.Bar < 42
es equivalente a
foo.Bar.GetValueOrDefault() < 42 && foo.Bar.HasValue
excepto que foo.Bar
solo tiene acceso una vez. (Lo obtuve descompilando el programa en Reflector. Es interesante que el compilador elija realizar la comparación antes de comprobar si es nulo, pero tiene sentido como una microoptimización).
Si el tipo de foos
tiempo de foos
es foos
IQueryable<Foo>
, entonces foo.Bar < 42
es equivalente a
foo.Bar < (int?)42
y depende del proveedor de LINQ si se comprueba si hay valores nulos y de qué manera.
ACTUALIZACIÓN: si el tipo de foo.Bar
es bool?
y solo quiere incluir registros donde foo.Bar
es verdadero (es decir, ni falso ni nulo), entonces puede escribir
foos.Where(foo => foo.Bar == true)
o
foos.Where(foo => foo.Bar.GetValueOrDefault())