Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
Depois que uma consulta LINQ é criada por um usuário, ela é convertida em uma árvore de comandos. Uma árvore de comandos é uma representação de uma consulta compatível com o Entity Framework. Em seguida, a árvore de comando é executada na fonte de dados. No momento da execução da consulta, todas as expressões de consulta (ou seja, todos os componentes da consulta) são avaliadas, incluindo as expressões usadas na materialização do resultado.
Em que ponto as expressões de consulta são executadas pode variar. As consultas LINQ são sempre executadas quando a variável de consulta é iterada, não quando a variável de consulta é criada. Isso é chamado de execução adiada. Você também pode forçar uma consulta a ser executada imediatamente, o que é útil para armazenar em cache os resultados da consulta. Isso é descrito posteriormente neste tópico.
Quando uma consulta LINQ to Entities é executada, algumas expressões na consulta podem ser executadas no servidor e algumas partes podem ser executadas localmente no cliente. A avaliação do lado do cliente de uma expressão ocorre antes que a consulta seja executada no servidor. Se uma expressão for avaliada no cliente, o resultado dessa avaliação será substituído pela expressão na consulta e a consulta será executada no servidor. Como as consultas são executadas na fonte de dados, a configuração da fonte de dados substitui o comportamento especificado no cliente. Por exemplo, o tratamento de valor nulo e a precisão numérica dependem das configurações do servidor. Todas as exceções geradas durante a execução da consulta no servidor são passadas diretamente para o cliente.
Dica
Para obter um resumo conveniente dos operadores de consulta no formato de tabela, que permite identificar rapidamente o comportamento de execução de um operador, consulte Classificação de operadores de consulta padrão por modo de execução (C#).
Execução de consulta adiada
Em uma consulta que retorna uma sequência de valores, a variável de consulta em si nunca mantém os resultados da consulta e armazena apenas os comandos de consulta. A execução da consulta é adiada até que a variável de consulta seja iterada em um loop foreach ou For Each. Isso é conhecido como execução adiada; ou seja, a execução da consulta ocorre algum tempo depois que a consulta é construída. Isso significa que você pode executar uma consulta com a frequência que desejar. Isso é útil quando, por exemplo, você tem um banco de dados que está sendo atualizado por outros aplicativos. Em seu aplicativo, você pode criar uma consulta para recuperar as informações mais recentes e executar repetidamente a consulta, retornando as informações atualizadas todas as vezes.
A execução adiada permite que várias consultas sejam combinadas ou uma consulta seja estendida. Quando uma consulta é estendida, ela é modificada para incluir as novas operações e a execução eventual refletirá as alterações. No exemplo a seguir, a primeira consulta retorna todos os produtos. A segunda consulta estende a primeira usando Where para retornar todos os produtos de tamanho "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
Depois que uma consulta tiver sido executada, todas as consultas sucessivas usarão os operadores LINQ na memória. Iterar sobre a variável de consulta usando uma instrução foreach ou For Each ou chamando um dos operadores de conversão LINQ fará com que a execução seja imediata. Esses operadores de conversão incluem o seguinte: ToList, , ToArraye ToLookupToDictionary.
Execução imediata da consulta
Em contraste com a execução adiada de consultas que produzem uma sequência de valores, as consultas que retornam um valor singleton são executadas imediatamente. Alguns exemplos de consultas singleton são Average, Counte FirstMax. Essas consultas são executadas imediatamente porque a consulta deve gerar uma sequência para calcular o resultado singleton. Você também pode forçar a execução imediata. Isso é útil quando você deseja armazenar em cache os resultados de uma consulta. Para forçar a execução imediata de uma consulta que não produz um valor único, você pode chamar o método ToList, o método ToDictionary ou o método ToArray em uma consulta ou em uma variável de consulta. O exemplo a seguir usa o ToArray método para avaliar imediatamente uma sequência em uma matriz.
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
Você também pode forçar a execução colocando o loop foreach ou For Each imediatamente após a expressão de consulta, mas, ao chamar ToList ou ToArray, você armazena todos os dados em cache em um único objeto de coleção.
Execução de armazenamento
Em geral, expressões em LINQ to Entities são avaliadas no servidor, e não se deve esperar que o comportamento da expressão siga a semântica do CLR (Common Language Runtime), mas sim a da fonte de dados. No entanto, há exceções a isso, como quando a expressão é executada no cliente. Isso pode causar resultados inesperados, por exemplo, quando o servidor e o cliente estão em fusos horários diferentes.
Algumas expressões na consulta podem ser executadas no cliente. Em geral, espera-se que a maior parte da execução de consulta ocorra no servidor. Além dos métodos executados em relação aos elementos de consulta mapeados para a fonte de dados, geralmente há expressões na consulta que podem ser executadas localmente. A execução local de uma expressão de consulta gera um valor que pode ser usado na execução da consulta ou na construção do resultado.
Determinadas operações são sempre executadas no cliente, como a associação de valores, as subexpressões, as subconsultas de fechamentos e a materialização de objetos nos resultados da consulta. O resultado final disso é que esses elementos (por exemplo, parâmetros de valores) não podem ser atualizados durante a execução. Tipos anônimos podem ser criados diretamente na fonte de dados, mas não se deve assumir que será o caso. Os agrupamentos embutidos podem ser construídos na fonte de dados, também, mas isso não deve ser suposto em cada instância. Em geral, é melhor não fazer suposições sobre o que é construído no servidor.
Esta seção descreve os cenários em que o código é executado localmente no cliente. Para obter mais informações sobre quais tipos de expressões são executadas localmente, consulte Expressões no LINQ to Entities Queries.
Literais e parâmetros
Variáveis locais, como a orderID variável no exemplo a seguir, são avaliadas no cliente.
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
Os parâmetros de método também são avaliados no cliente. O orderID parâmetro passado para o MethodParameterExample método, abaixo, é um exemplo.
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
Literais de conversão no cliente
A conversão de null para um tipo CLR é executada no cliente.
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
A conversão em um tipo, como Decimal anulável, é executada no cliente:
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
Construtores de literais
Novos tipos CLR que podem ser mapeados para tipos de modelo conceitual são executados no cliente:
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
Novas matrizes também são executadas no cliente.
Armazenar exceções
Todos os erros de repositório encontrados durante a execução da consulta são passados para o cliente e não são mapeados ou manipulados.
Configuração do repositório
Quando a consulta é executada no repositório, a configuração do repositório substitui todos os comportamentos do cliente e a semântica do repositório é expressa para todas as operações e expressões. Isso pode resultar em uma diferença no comportamento entre o CLR e a execução do repositório em áreas como comparações de valores nulos, ordenação GUID, precisão e exatidão de operações que envolvem tipos de dados não precisos (como tipos de ponto flutuante ou DateTime) e operações com cadeias de caracteres. É importante ter isso em mente ao examinar os resultados da consulta.
Por exemplo, veja a seguir algumas diferenças de comportamento entre o CLR e o SQL Server:
O SQL Server ordena GUIDs de forma diferente do CLR.
Também pode haver diferenças na precisão do resultado ao lidar com o tipo Decimal no SQL Server. Isso ocorre devido aos requisitos de precisão fixos do tipo decimal do SQL Server. Por exemplo, a média dos Decimal valores 0.0, 0.0 e 1.0 é 0,333333333333333333333333333333333333 na memória no cliente, mas 0,3333333 no repositório (com base na precisão padrão do tipo decimal do SQL Server).
Algumas operações de comparação de cadeia de caracteres também são tratadas de forma diferente no SQL Server do que no CLR. O comportamento de comparação de cadeia de caracteres depende das configurações de ordenação no servidor.
As chamadas de função ou método, quando incluídas em uma consulta LINQ to Entities, são mapeadas para funções canônicas no Entity Framework, que são traduzidas para Transact-SQL e executadas no banco de dados do SQL Server. Há casos em que o comportamento que essas funções mapeadas exibem pode ser diferente da implementação nas bibliotecas de classe base. Por exemplo, chamar o Contains, StartsWithe EndsWith métodos com uma cadeia de caracteres vazia como um parâmetro retornará
truequando executado no CLR, mas retornaráfalsequando executado no SQL Server. O EndsWith método também pode retornar resultados diferentes porque o SQL Server considera duas cadeias de caracteres iguais se elas forem diferentes apenas no espaço em branco à direita, enquanto o CLR as considera não iguais. Isso é ilustrado pelo seguinte exemplo:
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