EF4: A consulta de entidades LINQ 2 funciona em C #, mas não no VB
[EDITADO: Deixei a pergunta original abaixo, com mais contexto e código para reproduzir o problema. A versão curta abaixo contém a essência da pergunta]
Versão curta: a consulta abaixo gera um System.NotSupportedException: "Não foi possível converter o tipo 'System.Linq.IOrderedQueryable1' to type 'System.Linq.IQueryable
1 '. O LINQ to Entities suporta apenas a conversão de tipos primitivos do Modelo de Dados de Entidade. "A exceção é gerada apenas na versão VB.Net. Quando traduzida para C #, nenhuma exceção é gerada.
Dim doesThisCrash = From outerOrder In orders
Where outerOrder.ProductId =
(From p In products Join o In orders On p.Id Equals o.ProductId
Order By p.Id
Select p.Id).FirstOrDefault()
Select outerOrder
doesThisCrash.ToList()
Portanto, para travar, parece que precisamos de uma subconsulta em que o ObjectSet original (pedidos) seja associado a outro ObjectSet (produtos) e pedido. Ao usar apenas os pedidos ou os produtos definidos, nenhuma falha ocorre. Ao deixar de fora o Order By, também não há falha.
Estou inclinado a pensar que este é um bug do compilador (VB.Net), a menos que haja algo óbvio que estou ignorando aqui ...
Por enquanto minha pergunta ainda permanece:
por que uma mesma consulta aparentemente exata funciona em c #, mas não no VB?essa consulta pode ser feita para funcionar no VB.Net?[/EDITAR]
Versão opcional mais longa (pergunta original):
Meu domínio parece muito diferente, mas traduzi o problema para uma versão mais simples, com as seguintes entidades (nota: na verdade, eu as defini usando o designer .edmx, portanto, essa é uma versão simplificada):
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime DateCreated { get; set; }
}
public class Order
{
public int Id { get; set; }
public int CustomerId { get; set; }
public int ProductId { get; set; }
public DateTime OrderDate { get; set; }
}
public class Customer
{
public int Id { get; set; }
}
Estou tentando elaborar uma consulta de linq para entidades que deve parecer estruturalmente assim, no VB.Net:
Dim db = New SampleEntities()
Dim orders As IQueryable(Of Order) = db.Orders
Dim products As IQueryable(Of Product) = db.Products
Dim currentDate = DateTime.Now
Dim qLinq = From outerOrder In orders
Where outerOrder.OrderDate = currentDate AndAlso
outerOrder.ProductId =
(From p In products Join o In orders On p.Id Equals o.ProductId
Where o.OrderDate = outerOrder.OrderDate AndAlso
outerOrder.CustomerId = o.CustomerId
Order By p.DateCreated
Select p.Id).FirstOrDefault()
Select outerOrder
Isso gera uma System.NotSupportedException:
"Não foi possível converter o tipo 'System.Linq.IOrderedQueryable1' to type 'System.Linq.IQueryable
1 '. O LINQ to Entities suporta apenas a transmissão de tipos primitivos do Modelo de Dados da Entidade. "
Ao deixar de fora a parte 'Order By', nenhuma exceção é gerada.
Realmente não vejo uma razão pela qual essa consulta não seja suportada ... Então decidi tentar a mesma coisa em c #:
var qLinq = from oOut in orders
where oOut.OrderDate == currentDate
&& oOut.ProductId ==
(from p in products join o in orders on p.Id equals o.ProductId
where oOut.OrderDate == o.OrderDate
&& oOut.CustomerId == o.CustomerId
orderby p.DateCreated
select p.Id).FirstOrDefault()
select oOut;
Para minha surpresa, isso funciona! Traduzi a consulta C # para a sintaxe do método de extensão e, em seguida, voltei ao VB, mas obtive os mesmos resultados (a versão C # funciona, a versão VB.Net gera a mesma exceção).
Acho que minha pergunta é dupla:
por que uma mesma consulta aparentemente exata funciona em c #, mas não no VB?essa consulta pode ser feita para funcionar no VB.Net?Para referência, aqui estão as consultas na sintaxe do método de extensão:
Versão c #:
var q = orders.Where(outerOrder =>
outerOrder.OrderDate == currentDate &&
outerOrder.ProductId ==
(products
.Join(orders,
f => f.Id,
o => o.ProductId,
(f, o) => new { f, o })
.Where(t => t.o.OrderDate == outerOrder.OrderDate
&& outerOrder.CustomerId == t.o.CustomerId)
.OrderByDescending(t => t.f.DateCreated)
.Select(t => t.f.Id))
.FirstOrDefault());
Versão VB.Net:
Dim q = orders.Where(Function(outerOrder) outerOrder.OrderDate = currentDate AndAlso
outerOrder.ProductId = (products.Join(orders,
Function(p) p.Id,
Function(o) o.ProductId,
Function(p, o) New With {.p = p, .o = o}).
Where(Function(x) x.o.OrderDate = outerOrder.OrderDate AndAlso
outerOrder.CustomerId = x.o.CustomerId).
OrderByDescending(Function(x) x.p.DateCreated).
Select(Function(x) x.p.Id).
FirstOrDefault()))