with inner framework firstordefault sql linq entity-framework ienumerable linq-to-objects

inner - sql command entity framework



Con Entity Framework, ¿es mejor usar.First() o.Take(1) para "TOP 1"? (5)

Estamos implementando algunos repositorios de datos de EF, y tenemos algunas consultas que incluirían TOP 1

He leído muchas publicaciones que sugieren usar .Take(1)
El código que estoy revisando usa .First()

Entiendo que ambos producen el mismo resultado para la asignación de objetos, pero ¿ambos resuelven la misma consulta? Cuando se consulta el DB, ¿estará realmente con TOP 1 para ambas solicitudes? ¿O ejecutarán la consulta en su totalidad en el enumerable, y luego simplemente tomarán la primera entrada en la colección?

Además, si usamos .FirstOrDefault() entonces ¿por qué deberíamos esperar un comportamiento diferente? Sé que al usar un IEnumerable, se .First() en una colección vacía, pero si esto solo cambia la consulta para incluir TOP 1 entonces no esperaría absolutamente ninguna diferencia funcional entre .First() y .FirstOrDefault() .... ¿verdad?

Alternativamente, ¿hay algún método mejor que estas extensiones enumerables para hacer que la consulta ejecute TOP 1 ?


Cómo funciona .First() :

Si la colección es de tipo IList, se accede al primer elemento por posición de índice, que es diferente según la implementación de la colección. De lo contrario, un iterador devuelve el primer elemento.

Y .Take(int count) siempre itera.

Si hay alguna ganancia, sucede si la colección implementa IList y la velocidad para acceder al primer elemento por índice es más alta que la de devolver un iterador. No creo que sea significativo. ;)

Fuentes:

http://www.hookedonlinq.com/FirstOperator.ashx

http://www.hookedonlinq.com/TakeOperator.ashx


Desde LINQPad :

C # :

age_Centers.Select(c => c.Id).First(); age_Centers.Select(c => c.Id).FirstOrDefault(); age_Centers.Select(c => c.Id).Take(1).Dump();

SQL :

SELECT TOP (1) [t0].[Id] FROM [age_Centers] AS [t0] GO SELECT TOP (1) [t0].[Id] FROM [age_Centers] AS [t0] GO SELECT TOP (1) [t0].[Id] FROM [age_Centers] AS [t0]

* Tenga en cuenta que Take(1) enumera y devuelve un IQueryable .


Primero consultará la Toma 1, por lo que no hay diferencia en la consulta. Llamar a FirstOrDefault será una declaración de un paso, porque Take returns IEnumerable necesitará llamar a First de todos modos.

Primero arrojará una excepción, por lo que siempre se prefiere FirstOrDefault.

Y, por supuesto, las personas que escribieron el convertidor de consultas de EF son lo suficientemente inteligentes como para llamar a Take 1 en lugar de ejecutar el conjunto de resultados completo y devolver el primer elemento.

Puede verificar esto usando el generador de perfiles SQL.


Redirija la propiedad del Log DataContext a Console.Out o a un TextFile y vea qué consulta produce cada opción.


**First()** operates on a collection of any number of objects and returns the first object. **Take(1)** operates on a collection of any number of objects and returns a collection containing the first object.

También puede usar Single Single () opera en una colección de exactamente un objeto y simplemente devuelve el objeto.