[EDITED: I left the original question below, with some more context and code to reproduce the problem. The short version below contains the essence of the question]
Short version: the query below throws a System.NotSupportedException: "Unable to cast the type 'System.Linq.IOrderedQueryable1' to type 'System.Linq.IQueryable
1'. LINQ to Entities only supports casting Entity Data Model primitive types." The exception is only raised in the VB.Net version. When translated to C#, no exception is raised.
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()
So, to make it crash, it seems that we need a subquery where the original ObjectSet (orders) is joined with another ObjectSet (products), and ordered. When using just the orders or the products set, no crash occurs. When leaving out the Order By, also no crash.
I'm inclined to think this is a (VB.Net) compiler bug, unless there is something obvious that I'm overlooking here...
For now my question still stands:
[/EDIT]
Optional, longer version (original question):
My domain looks very different, but I translated the problem to a simpler version, with the following entities (note: I actually defined these using the .edmx designer, so this is a simplified version):
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; }
}
I'm trying to work out a linq-to-entities query that should strucurally look like this, in 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
This raises a System.NotSupportedException:
"Unable to cast the type 'System.Linq.IOrderedQueryable1' to type 'System.Linq.IQueryable
1'. LINQ to Entities only supports casting Entity Data Model primitive types."
When leaving out the 'Order By' part, no exception is raised.
I don't really see a reason why this query would not be supported... So I decided to try the same thing in 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;
To my surprise, this works! Then I translated the C# query to extension method syntax, and then back to VB, but got the same results (the C# version works, the VB.Net version raises the same exception).
So I guess my question is twofold:
For reference, here are the queries in extension method syntax:
C# version:
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());
VB.Net version:
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()))
LINQ to Entities queries are comprised of LINQ standard query operators (such as Select, Where, and GroupBy) and expressions (x > 10, Contact. LastName, and so on). LINQ operators are not defined by a class, but rather are methods on a class. In LINQ, expressions can contain anything allowed by types within the System.
There are two basic ways to write a LINQ query to IEnumerable collection or IQueryable data sources.
Types such as ArrayList that support the non-generic IEnumerable interface can also be used as a LINQ data source.
A single query expression may have multiple where clauses.
I think the following works, the SQL is ugly though:
Dim qLinq = From outerOrder In orders
Where outerOrder.OrderDate = currentDate AndAlso
outerOrder.ProductId =
(From x In (From p In products
Join o In orders On p.Id Equals o.ProductId
Where o.OrderDate = outerOrder.OrderDate AndAlso
outerOrder.CustomerId = o.CustomerId
Select p.Id)
Order By x).FirstOrDefault()
Select outerOrder
Does this work?
Dim a = From p In products Join o In orders On p.Id Equals o.ProductId
Order By p.DateCreated
Select New With {.id = p.Id, .OrderDate = o.OrderDate, .CustomerId = o.CustomerId, .DateCreated = p.DateCreated}
Dim b = From outerOrder In orders _
Where outerOrder.OrderDate = currentDate _
AndAlso outerOrder.ProductId = _
(From x In a Where x.OrderDate = outerOrder.OrderDate _
AndAlso x.CustomerId = outerOrder.CustomerId _
Select x.id).FirstOrDefault
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With