Entity Framework – Queries com Expression<Func<T, bool>> e Func<T, bool>

Apesar dos dois tipos de dados compilarem normalmente quando os utilizamos em um query method, existe uma diferença no modo como as queries do Entity Framework são criadas quando utilizamos Expression<Func<T, bool>> e Func<T, bool>.

frajola

Quando utilizamos Expression<Func<T, bool>> o Entity Framework reconhece a expressão existente e a transforma em código SQL.

Mas, quando utilizamos Func<T, bool>, a função é compilada em Intermediate Language, e não é transformada em código SQL. Desta forma o filtro é feita em memória, logo após o load dos dados vindos do banco de dados.

Veja os dois métodos a seguir:

public IEnumerable<PostBlog> BadQuery(Func<PostBlog, bool> predicate) {

    using (var context = new DatabaseContext()) {

        var query = context.PostBlogs.Where(predicate);
                
        return query.ToList();
    }
}

public IEnumerable<PostBlog> GoodQuery(Expression<Func<PostBlog, bool>> predicate) {

    using (var context = new DatabaseContext()) {

        var query = context.PostBlogs.Where(predicate);
                
        return query.ToList();
    }
}

Ambos os métodos são bastante semelhantes, exceto pelo nome do método e o tipo de dados de seu parâmetro de entrada. Para este exemplo ambos os métodos são invocados com a mesma entrada, conforme apresentado abaixo:

var r1 = repository.BadQuery(p => p.Title == "entity framework");

var r2 = repository.GoodQuery(p => p.Title == "entity framework");

Mesmo com a mesma expressão lambda sendo utilizada em ambos os métodos, o código SQL gerado é diferente. O código gerado pelo Entity Framework para o método BadQuery é o código apresentado a baixo:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Title] AS [Title], 
    [Extent1].[Body] AS [Body]
    FROM [dbo].[PostBlogs] AS [Extent1]

… e o código SQL gerado para o método GoodQuery é o código apresentado a seguir:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[Title] AS [Title], 
    [Extent1].[Body] AS [Body]
    FROM [dbo].[PostBlogs] AS [Extent1]
    WHERE (N'entity framework' = [Extent1].[Title]) 
	   AND ([Extent1].[Title] IS NOT NULL)

Note que o código SQL gerado para o método BadQuery não possui filtros, desta forma o EF consulta todos os registros e os filtra em memória. Enquanto que o método GoodQuery faz o filtro no código SQL (o que acarreta em um carregamento mais rápidos dos dados, além de economias de memória e processamento).

Por isso, revejam o modo como passam critérios dinâmicos para consultas do Entity Framework. É possível que a sua aplicação esteja consumindo mais recursos do que o necessário.

FH

4 comentários sobre “Entity Framework – Queries com Expression<Func<T, bool>> e Func<T, bool>

  1. Eae Fê, blz cara?!

    Mano, parabéns pelo excelente post – poucos lugares falam sobre esta “sutil” diferença, mas que transformam um sistema da água para o vinho, como foi um agora que entreguei.

    Valeu e Abs!

Deixar mensagem para João Luiz Ribeiro Cancelar resposta

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.