Ejecución de la consultaQuery Execution

Una vez creada por un usuario una consulta LINQ, se convierte en un árbol de comandos.After a LINQ query is created by a user, it is converted to a command tree. Un árbol de comandos es una representación de una consulta que es compatible con Entity Framework.A command tree is a representation of a query that is compatible with the Entity Framework. Posteriormente, el árbol de comandos se ejecuta en el origen de datos.The command tree is then executed against the data source. En el momento de la ejecución de la consulta, se evalúan todas las expresiones de consulta (es decir, todos los componentes de la consulta), incluidas las expresiones que se utilizan en la materialización del resultado.At query execution time, all query expressions (that is, all components of the query) are evaluated, including those expressions that are used in result materialization.

El momento en que se ejecutan las expresiones de consulta puede variar.At what point query expressions are executed can vary. Las consultas LINQ siempre se ejecutan cuando se recorre en iteración la variable de consulta, no cuando se crea la citada variable de consulta.LINQ queries are always executed when the query variable is iterated over, not when the query variable is created. Esto se denomina ejecución diferida.This is called deferred execution. También se puede obligar a que la consulta se ejecute inmediatamente, lo que es útil para almacenar en caché los resultados de la consulta.You can also force a query to execute immediately, which is useful for caching query results. Esto se describe más adelante en este tema.This is described later in this topic.

Cuando se ejecuta una consulta de LINQ to Entities, algunas de sus expresiones podrían ejecutarse en el servidor y ciertas partes podrían ejecutarse de forma local en el cliente.When a LINQ to Entities query is executed, some expressions in the query might be executed on the server and some parts might be executed locally on the client. La evaluación en el cliente de una expresión se lleva a cabo antes de ejecutar la consulta en el servidor.Client-side evaluation of an expression takes place before the query is executed on the server. Si una expresión se evalúa en el cliente, el resultado de esa evaluación se sustituye por la expresión en la consulta, y ésta se ejecuta entonces en el servidor.If an expression is evaluated on the client, the result of that evaluation is substituted for the expression in the query, and the query is then executed on the server. Dado que las consultas se ejecutan en el origen de datos, la configuración de este reemplaza el comportamiento especificado en el cliente.Because queries are executed on the data source, the data source configuration overrides the behavior specified in the client. Por ejemplo, la precisión numérica y el tratamiento de los valores NULL dependen de la configuración de servidor.For example, null value handling and numerical precision depend on the server settings. Cualquier excepción que se produzca durante la ejecución de la consulta en el servidor se pasa directamente al cliente.Any exceptions thrown during query execution on the server are passed directly up to the client.

Ejecución de consultas en diferidoDeferred query execution

En una consulta que devuelve una secuencia de valores, la variable de consulta por sí misma nunca conserva los resultados de la consulta y solo almacena los comandos de la misma.In a query that returns a sequence of values, the query variable itself never holds the query results and only stores the query commands. La ejecución de la consulta se aplaza hasta que la variable de consulta se recorre en iteración en un bucle foreach o For Each.Execution of the query is deferred until the query variable is iterated over in a foreach or For Each loop. Esto se conoce como ejecución diferida; es decir, la consulta la ejecución se produce después de que se cree la consulta.This is known as deferred execution; that is, query execution occurs some time after the query is constructed. Esto significa que se puede ejecutar una consulta con la frecuencia que se desee.This means that you can execute a query as frequently as you want to. Esto es útil cuando, por ejemplo, se tiene una base de datos que otras aplicaciones están actualizando.This is useful when, for example, you have a database that is being updated by other applications. En su aplicación puede crear una consulta para recuperar la información más reciente y ejecutar de forma repetida la consulta, devolviendo cada vez la información actualizada.In your application, you can create a query to retrieve the latest information and repeatedly execute the query, returning the updated information every time.

La ejecución aplazada permite combinar varias consultas o ampliar una consulta.Deferred execution enables multiple queries to be combined or a query to be extended. Cuando se amplía una consulta, se modifica para incluir las nuevas operaciones. La ejecución eventual reflejará los cambios.When a query is extended, it is modified to include the new operations, and the eventual execution will reflect the changes. En el siguiente ejemplo, la primera consulta devuelve todos los productos.In the following example, the first query returns all the products. La segunda consulta amplía la primera usando Where para devolver todos los productos del tamaño "L":The second query extends the first by using Where to return all the products of size "L":

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    IQueryable<Product> productsQuery =
        from p in context.Products
        select p;

    IQueryable<Product> largeProducts = productsQuery.Where(p => p.Size == "L");

    Console.WriteLine("Products of size 'L':");
    foreach (var product in largeProducts)
    {
        Console.WriteLine(product.Name);
    }
}
Using context As New AdventureWorksEntities()
    Dim productsQuery = _
        From p In context.Products _
        Select p

    Dim largeProducts = _
        productsQuery.Where(Function(p) p.Size = "L")

    Console.WriteLine("Products of size 'L':")
    For Each product In largeProducts
        Console.WriteLine(product.Name)
    Next
End Using

Una vez ejecutada una consulta, todas las consultas sucesivas utilizarán los operadores de LINQ en memoria.After a query has been executed all successive queries will use the in-memory LINQ operators. Si se recorre en iteración la variable de la consulta utilizando una instrucción foreach o For Each o llamando a uno de los operadores de conversión de LINQ, se producirá la ejecución inmediata.Iterating over the query variable by using a foreach or For Each statement or by calling one of the LINQ conversion operators will cause immediate execution. Entre estos operadores de conversión se incluyen los siguientes: ToList, ToArray, ToLookup y ToDictionary.These conversion operators include the following: ToList, ToArray, ToLookup, and ToDictionary.

Ejecución de consultas inmediataImmediate Query Execution

A diferencia de la ejecución aplazada de consultas que producen una secuencia de valores, las consultas que devuelven un valor singleton se ejecutan inmediatamente.In contrast to the deferred execution of queries that produce a sequence of values, queries that return a singleton value are executed immediately. Algunos ejemplos de consultas singleton son Average, Count, First y Max.Some examples of singleton queries are Average, Count, First, and Max. Se ejecutan inmediatamente porque la consulta debe producir una secuencia para calcular el resultado singleton.These execute immediately because the query must produce a sequence to calculate the singleton result. También se puede forzar la ejecución inmediata.You can also force immediate execution. Esto es útil cuando se desea almacenar en memoria caché los resultados de una consulta.This is useful when you want to cache the results of a query. Para forzar la ejecución inmediata de una consulta que no produce un valor singleton, se puede llamar a los métodos ToList, ToDictionary o ToArray en una consulta o una variable de consulta.To force immediate execution of a query that does not produce a singleton value, you can call the ToList method, the ToDictionary method, or the ToArray method on a query or query variable. En el ejemplo siguiente se utiliza el método ToArray para evaluar de forma inmediata una secuencia en una matriz.The following example uses the ToArray method to immediately evaluate a sequence into an array.

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    ObjectSet<Product> products = context.Products;

    Product[] prodArray = (
        from product in products
        orderby product.ListPrice descending
        select product).ToArray();

    Console.WriteLine("Every price from highest to lowest:");
    foreach (Product product in prodArray)
    {
        Console.WriteLine(product.ListPrice);
    }
}
Using context As New AdventureWorksEntities
    Dim products As ObjectSet(Of Product) = context.Products

    Dim prodArray As Product() = ( _
        From product In products _
        Order By product.ListPrice Descending _
        Select product).ToArray()

    Console.WriteLine("The list price from highest to lowest:")
    For Each prod As Product In prodArray
        Console.WriteLine(prod.ListPrice)
    Next
End Using

También se puede forzar la ejecución colocando el bucle foreach o For Each inmediatamente después de la expresión de consulta, pero si se llama a los métodos ToList o ToArray, se almacenarán en caché todos los datos de un solo objeto de la colección.You could also force execution by putting the foreach or For Each loop immediately after the query expression, but by calling ToList or ToArray you cache all the data in a single collection object.

Ejecución en el almacénStore Execution

En general, las expresiones de LINQ to Entities se evalúan en el servidor, y no es de esperar que el comportamiento de la expresión siga la semántica de Common Language Runtime (CLR), sino la del origen.In general, expressions in LINQ to Entities are evaluated on the server, and the behavior of the expression should not be expected to follow common language runtime (CLR) semantics, but those of the data source. Sin embargo, hay excepciones, como cuando la expresión se ejecuta en el cliente.There are exceptions to this, however, such as when the expression is executed on the client. Esto puede producir resultados inesperados, por ejemplo cuando el servidor y el cliente están en zonas horarias diferentes.This could cause unexpected results, for example when the server and client are in different time zones.

Algunas expresiones de la consulta se pueden ejecutar en el cliente.Some expressions in the query might be executed on the client. En general, se espera que la mayor parte de la ejecución de la consulta se produzca en el servidor.In general, most query execution is expected to occur on the server. Además de los métodos ejecutados en elementos de consulta asignados al origen de datos, suele haber expresiones de la consulta que se pueden ejecutar localmente.Aside from methods executed against query elements mapped to the data source, there are often expressions in the query that can be executed locally. La ejecución local de una expresión de consulta produce un valor que se puede utilizar en la ejecución de la consulta o en la generación del resultado.Local execution of a query expression yields a value that can be used in the query execution or result construction.

Ciertas operaciones se ejecutan siempre en el cliente, como el enlace de valores, subexpresiones, subconsultas de cierres, y la materialización de objetos en los resultados de la consulta.Certain operations are always executed on the client, such as binding of values, sub expressions, sub queries from closures, and materialization of objects into query results. La consecuencia final es que estos elementos (por ejemplo, los valores de parámetro) no se pueden actualizar durante la ejecución.The net effect of this is that these elements (for example, parameter values) cannot be updated during the execution. Los tipos anónimos se pueden crear alineados en el origen de datos, pero no se debe suponer que esto se vaya a producir.Anonymous types can be constructed inline on the data source, but should not be assumed to do so. Las agrupaciones alineadas también se pueden crear en el almacén, pero no se debe suponer que esto tenga lugar en cada instancia.Inline groupings can be constructed in the data source, as well, but this should not be assumed in every instance. En general, es preferible no hacer suposiciones sobre lo que se crea en el servidor.In general, it is best not to make any assumptions about what is constructed on the server.

En esta sección se describen los escenarios en que el código se ejecuta localmente en el cliente.This section describes the scenarios in which code is executed locally on the client. Para obtener más información acerca de qué tipos de expresiones se ejecutan localmente, consulte expresiones en consultas LINQ to Entities.For more information about which types of expressions are executed locally, see Expressions in LINQ to Entities Queries.

Literales y parámetrosLiterals and Parameters

Las variables locales, como la variable orderID del ejemplo siguiente, se evalúan en el cliente.Local variables, such as the orderID variable in the following example, are evaluated on the client.

int orderID = 51987;

IQueryable<SalesOrderHeader> salesInfo =
    from s in context.SalesOrderHeaders
    where s.SalesOrderID == orderID
    select s;
Dim orderID As Integer = 51987

Dim salesInfo = _
    From s In context.SalesOrderHeaders _
    Where s.SalesOrderID = orderID _
    Select s

Los parámetros de métodos también se evalúan en el cliente.Method parameters are also evaluated on the client. El parámetro orderID que se pasa al método MethodParameterExample, como se puede apreciar más abajo, es un ejemplo.The orderID parameter passed into the MethodParameterExample method, below, is an example.

public static void MethodParameterExample(int orderID)
{
    using (AdventureWorksEntities context = new AdventureWorksEntities())
    {
        
        IQueryable<SalesOrderHeader> salesInfo =
            from s in context.SalesOrderHeaders
            where s.SalesOrderID == orderID
            select s;                

        foreach (SalesOrderHeader sale in salesInfo)
        {
            Console.WriteLine("OrderID: {0}, Total due: {1}", sale.SalesOrderID, sale.TotalDue);
        }
    }
}
Function MethodParameterExample(ByVal orderID As Integer)
    Using context As New AdventureWorksEntities()

        Dim salesInfo = _
            From s In context.SalesOrderHeaders _
            Where s.SalesOrderID = orderID _
            Select s

        Console.WriteLine("Sales order info:")
        For Each sale As SalesOrderHeader In salesInfo
            Console.WriteLine("OrderID: {0}, Total due: {1}", sale.SalesOrderID, sale.TotalDue)
        Next
    End Using

End Function

Convertir literales en el clienteCasting Literals on the Client

La conversión de null a un tipo CLR se ejecuta en el cliente:Casting from null to a CLR type is executed on the client:

IQueryable<Contact> query =
    from c in context.Contacts
    where c.EmailAddress == (string)null
    select c;
Dim query = _
    From c In context.Contacts _
    Where c.EmailAddress = CType(Nothing, String) _
    Select c

La conversión a un tipo, como un Decimal que acepta valores NULL, se ejecuta en el cliente:Casting to a type, such as a nullable Decimal, is executed on the client:

var weight = (decimal?)23.77;
IQueryable<Product> query =
    from product in context.Products
    where product.Weight == weight
    select product;
Dim weight = CType(23.77, Decimal?)
Dim query = _
    From product In context.Products _
        Where product.Weight = weight _
        Select product

Constructores para literalesConstructors for Literals

Los nuevos tipos CLR que se pueden asignar a tipos del modelo conceptual se ejecutan en el cliente:New CLR types that can be mapped to conceptual model types are executed on the client:

var weight = new decimal(23.77);
IQueryable<Product> query =
    from product in context.Products
    where product.Weight == weight
    select product;
Dim weight = New Decimal(23.77)
Dim query = _
    From product In context.Products _
    Where product.Weight = weight _
    Select product

Las nuevas matrices también se ejecutan en el cliente.New arrays are also executed on the client.

Excepciones en el almacénStore Exceptions

Los errores en el almacén que tienen lugar durante la ejecución de la consulta se pasan al cliente y no se asignan ni controlan.Any store errors that are encountered during query execution are passed up to the client, and are not mapped or handled.

Configuración del almacénStore Configuration

Cuando la consulta se ejecuta en el almacén, la configuración del almacén invalida todos los comportamientos del cliente, y la semántica del almacén se expresa para todas las operaciones y expresiones.When the query executes on the store, the store configuration overrides all client behaviors, and store semantics are expressed for all operations and expressions. El resultado puede ser una diferencia de comportamiento entre la ejecución en el CLR y la ejecución en el almacén en áreas como las comparaciones de NULL, la ordenación de GUID, la precisión y la exactitud de las operaciones que afectan a tipos de datos no precisos (como los tipos de punto flotante o DateTime) y las operaciones de cadena.This can result in a difference in behavior between CLR and store execution in areas such as null comparisons, GUID ordering, precision and accuracy of operations involving non-precise data types (such as floating point types or DateTime), and string operations. Es importante tener esto en cuenta al examinar los resultados de la consulta.It is important to keep this in mind when examining query results.

Por ejemplo, a continuación se indican algunas diferencias de comportamiento entre CLR y SQL Server:For example, the following are some differences in behavior between the CLR and SQL Server:

  • SQL Server ordena los GUID de manera diferente que CLR.SQL Server orders GUIDs differently than the CLR.

  • También puede haber diferencias en la precisión del resultado cuando se trabaja con el tipo Decimal en SQL Server.There can also be differences in result precision when dealing with the Decimal type on SQL Server. Esto se debe a los requisitos de precisión fijados para el tipo decimal de SQL Server.This is due to the fixed precision requirements of the SQL Server decimal type. Por ejemplo, el valor medio de los valores Decimal 0.0, 0.0, y 1.0 es 0.3333333333333333333333333333 en memoria en el cliente, pero 0.333333 en el almacén (si se toma como base la precisión predeterminada para el tipo decimal de SQL Server).For example, the average of Decimal values 0.0, 0.0, and 1.0 is 0.3333333333333333333333333333 in memory on the client, but 0.333333 in the store (based on the default precision for SQL Server’s decimal type).

  • Algunas operaciones de comparación de cadenas también se tratan en SQL Server de forma diferente que en CLR.Some string comparison operations are also handled differently in SQL Server than in the CLR. El comportamiento de la comparación de cadenas depende de los valores de intercalación en el servidor.String comparison behavior depends on the collation settings on the server.

  • Las llamadas a funciones o métodos, cuando se incluyen en una consulta de LINQ to Entities, se asignan a funciones canónicas en Entity Framework, que, posteriormente, se convierten a Transact-SQL y se ejecutan en la base de datos de SQL Server.Function or method calls, when included in a LINQ to Entities query, are mapped to canonical functions in the Entity Framework, which are then translated to Transact-SQL and executed on the SQL Server database. Hay casos en que el comportamiento que muestran estas funciones asignadas puede diferir de la implementación en las bibliotecas de clases base.There are cases when the behavior these mapped functions exhibit might differ from the implementation in the base class libraries. Por ejemplo, una llamada a los métodos Contains, StartsWith y EndsWith con una cadena vacía como parámetro, devolverá true si se ejecuta en CLR pero devolverá false si se ejecuta en SQL Server.For example, calling the Contains, StartsWith, and EndsWith methods with an empty string as a parameter will return true when executed in the CLR, but will return false when executed in SQL Server. El método EndsWith también puede devolver resultados diferentes porque SQL Server considera que dos cadenas son iguales si solo se diferencian en el espacio en blanco final, mientras que CLR considera que no son iguales.The EndsWith method can also return different results because SQL Server considers two strings to be equal if they only differ in trailing white space, whereas the CLR considers them to be not equal. Esto se muestra en el ejemplo siguiente:This is illustrated by the following example:

using (AdventureWorksEntities context = new AdventureWorksEntities())
{
    IQueryable<string> query = from p in context.Products
                               where p.Name == "Reflector"
                               select p.Name;

    IEnumerable<bool> q = query.Select(c => c.EndsWith("Reflector "));

    Console.WriteLine("LINQ to Entities returns: " + q.First());
    Console.WriteLine("CLR returns: " + "Reflector".EndsWith("Reflector "));

}
Using context As New AdventureWorksEntities()

    Dim query = _
        From p In context.Products _
        Where p.Name = "Reflector" _
        Select p.Name

    Dim q = _
        query.Select(Function(c) c.EndsWith("Reflector "))

    Console.WriteLine("LINQ to Entities returns: " & q.First())
    Console.WriteLine("CLR returns: " & "Reflector".EndsWith("Reflector "))
End Using