Pregunta

Hablando como programador que no es experto en C#, tengo curiosidad por conocer la semántica de evaluación de consultas LINQ como las siguientes:

var people = from p in Person
             where p.age < 18
             select p

var otherPeople = from p in people
                  where p.firstName equals "Daniel"
                  select p

Asumiendo que Person es una entidad ADO que define la age y firstName campos, ¿qué haría esto desde el punto de vista de la base de datos?Específicamente, ¿la people La consulta se ejecutará para producir una estructura en memoria, que luego sería consultada por el otherPeople ¿consulta?¿O sería la construcción de otherPeople simplemente extraiga los datos relacionados con la consulta de people y luego producir una nueva consulta de base de datos?Entonces, si repito ambas consultas, ¿cuántas declaraciones SQL se ejecutarían?

¿Fue útil?

Solución

Son componibles.Esto es posible porque las consultas LINQ son en realidad expresiones (código como datos), que los proveedores de LINQ como LINQ-to-SQL pueden evaluar y generar el SQL correspondiente.

Debido a que las consultas LINQ se evalúan de forma diferida (p. ej.no se ejecutará hasta que repita los elementos), el código que mostró en realidad no tocará la base de datos.Hasta que no itere sobre otras personas o personas no se generará y ejecutará SQL.

Otros consejos

Sí, la consulta resultante está compuesta.Incluye la cláusula donde completa.Active la creación de perfiles SQL y pruébelo usted mismo.

Linq hace esto a través de árboles de expresión.La primera declaración linq produce un árbol de expresión;no ejecuta la consulta.La segunda declaración linq se basa en el árbol de expresión creado por la primera.La declaración solo se ejecuta cuando enumera la colección resultante.

var people = from p in Person
             where p.age < 18
             select p

Se traduce a:

SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0]
WHERE [t0].[Age] < @p0

donde @p0 se envía como 18

var otherPeople = from p in people
                  where p.firstName equals "Daniel"
                  select p

Se traduce a:

SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0]
WHERE [t0].[FirstName] = @p0

donde @p0 se envía como "Daniel"

var morePeople = from p1 in people
                 from p2 in otherPeople
                 where p1.PersonId == p2.PersonId
                 select p1;

Se traduce a:

SELECT [t0].[PersonId], [t0].[Age], [t0].[FirstName]
FROM [dbo].[Person] AS [t0], [dbo].[Person] AS [t1]
WHERE ([t0].[PersonId] = [t1].[PersonId]) AND ([t0].[Age] < @p0) AND ([t1].[FirstName] = @p1)

donde @p0 es 18, @p1 es "Daniel"

En caso de duda, llame a ToString() en su IQueryable o proporcione un TextWriter a la propiedad Log de DataContext.

people y otherPeople contener objetos de tipo IQueryable<Person>.

Si itera sobre ambos, por separado, ejecutará dos consultas.Si solo iteras otherPeople, ejecutará la consulta esperada, con dos cláusulas donde.

Si lo haces .ToList() en people y usar el devuelto List<Person> en la segunda consulta en lugar de personas, se convierte en LINQ-to-Objects y no se ejecuta ningún SQL.

Este comportamiento se conoce como ejecución diferida.Lo que significa que no se realiza ninguna consulta hasta que sea necesaria.Antes de la ejecución, son sólo árboles de expresión que se manipulan para formular la consulta final.

Ambas consultas se ejecutarán cuando intente acceder a los resultados finales.Puede intentar ver el SQL original generado a partir de las propiedades del objeto DataContext.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top