Sabe aquele obstáculo que parece ser a coisa mais simples do mundo?
Pois é! Em um novo projeto com EF 1.0 surgiu uma necessidade simples, fazer um select utilizando Linq to Entites que retornasse todos os ids de um array de inteiro , como no exemplo abaixo:
static void Main(string[] args)
{
NorthwindEntities context = new NorthwindEntities();
int[] ids = new int[] { 1, 2, 3 };
var resultado = from product in context.Products
where ids.Contains(product.ProductID)
select product;
foreach (var item in resultado)
Console.WriteLine("Nome: {0}", item.ProductName);
Console.Read();
}
Super simples, esse código inclusive funciona perfeitamente no L2Q, mais no EF 1.0 uma exception do tipo NotSupportedException é lançada com a seguinte mensagem de erro:
"LINQ to Entities não reconhece o método 'Boolean Contains[Int32](System.Collections.Generic.IEnumerable`1[System.Int32], Int32)', que não pode ser convertido em uma expressão de armazenamento."
Fui pesquisar como resolver esse problema e a maioria das soluções que encontrei "cheirava mal", e as que não tinha cheiro nenhum eram complicadas demais para um problema tão pontual, quase todas as soluções seguia a lógica abaixo , com pouquíssimas variações.
static void Main(string[] args)
{
NorthwindEntities context = new NorthwindEntities();
int[] ids = new int[] { 1, 2, 3 };
var resultado = from product in context.Products.AsEnumerable()
where ids.Contains(product.ProductID)
select product;
foreach (var item in resultado)
Console.WriteLine("Nome: {0}", item.ProductName);
Console.Read();
}
Note a presença do método AsEnumerable() isso resolveu o problema, mais conversando com outra pessoa questionei que esse código provavelmente trazia todos os dados da tabela para depois aplicar o filtro.
Utilize uma ferramenta open source http://code.google.com/p/sqlexpressprofiler/ para verifica se a afirmação estava correta, veja abaixo a consulta SQL gerada.
SELECT 1 AS [C1],
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[QuantityPerUnit] AS [QuantityPerUnit],
[Extent1].[UnitPrice] AS [UnitPrice],
[Extent1].[UnitsInStock] AS [UnitsInStock],
[Extent1].[UnitsOnOrder] AS [UnitsOnOrder],
[Extent1].[ReorderLevel] AS [ReorderLevel],
[Extent1].[Discontinued] AS [Discontinued],
[Extent1].[CategoryID] AS [CategoryID],
[Extent1].[SupplierID] AS [SupplierID]
FROM [dbo].[Products] AS [Extent1]
Para tudo! Select sem where e pedi para DBA pegar no seu pé e "tacar o pau" em todos ORMs do mundo!
Eu resolvi esse problema utilizando Entity SQL, veja o código abaixo:
static void Main(string[] args)
{
NorthwindEntities context = new NorthwindEntities();
var resultado = context.Products.Where("it.ProductID IN {1,2,3}");
foreach (var item in resultado)
Console.WriteLine("Nome: {0}", item.ProductName);
Console.Read();
}
Talvez a minha solução não seja a mais adequada mais com certeza o select será gerado de forma correta, para finalizar eu tenho uma boa noticia nada disso é problema para o EF 4, então corra para VS 2010!
Daniel Fonseca Castro