EF4:LINQ 2实体查询在C#中工作,但在VB中不工作

[编辑:我在下面留下了原始问题,有一些更多的上下文和代码来重现问题。 下面的简短版本包含问题的本质]

简短版本:下面的查询抛出一个System.NotSupportedException:“无法将类型’System.Linq.IOrderedQueryable 1' to type 'System.Linq.IQueryable强制转换1' to type 'System.Linq.IQueryable to Entities仅支持转换实体数据模型基元类型。” 仅在VB.Net版本中引发exception。 转换为C#时,不会引发exception。

  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() 

因此,为了使其崩溃,似乎我们需要一个子查询,其中原始ObjectSet(订单)与另一个ObjectSet(产品)连接,并且有序。 仅使用订单或产品集时,不会发生崩溃。 当省略Order By时,也没有崩溃。

我倾向于认为这是一个(VB.Net)编译器错误,除非有一些明显我在这里忽略的东西……

现在我的问题仍然存在:

  • 为什么一个看似完全相同的查询在C#中工作但在VB中不起作用?
  • 这个查询可以在VB.Net中工作吗?

[/编辑]

可选,更长版本(原始问题):

我的域看起来非常不同,但我将问题转换为更简单的版本,具有以下实体(注意:我实际上使用.edmx设计器定义了这些,因此这是一个简化版本):

  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; } } 

我正在尝试在VB.Net中找出一个linq-to-entities查询,它应该在结构上看起来像这样:

  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 

这会引发System.NotSupportedException:

“无法将类型’System.Linq.IOrderedQueryable 1' to type 'System.Linq.IQueryable强制转换1' to type 'System.Linq.IQueryable to Entities仅支持转换实体数据模型基元类型。”

当省略’Order By’部分时,不会引发任何例外。

我真的没有看到为什么不支持这个查询的原因…所以我决定在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; 

令我惊讶的是,这有效! 然后我将C#查询转换为扩展方法语法,然后转回VB,但得到了相同的结果(C#版本工作,VB.Net版本引发了相同的exception)。

所以我想我的问题是双重的:

  • 为什么一个看似完全相同的查询在C#中工作但在VB中不起作用?
  • 这个查询可以在VB.Net中工作吗?

供参考,以下是扩展方法语法中的查询:

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 => toOrderDate == outerOrder.OrderDate && outerOrder.CustomerId == toCustomerId) .OrderByDescending(t => tfDateCreated) .Select(t => tfId)) .FirstOrDefault()); 

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) xoOrderDate = outerOrder.OrderDate AndAlso outerOrder.CustomerId = xoCustomerId). OrderByDescending(Function(x) xpDateCreated). Select(Function(x) xpId). FirstOrDefault())) 

按照我编辑的答案Order By p.DateCreated行移动Order By p.DateCreated允许查询无任何exception地运行。 但是,发出的SQL是不同的,所以我认为你没有得到正确的结果。

 Dim qLinq = From outerOrder In orders Let id = (From p In products Order By p.DateCreated Join o In orders On p.Id Equals o.ProductId Where o.OrderDate = outerOrder.OrderDate AndAlso outerOrder.CustomerId = o.CustomerId Select p.Id).FirstOrDefault() Where outerOrder.OrderDate = currentDate AndAlso outerOrder.ProductId = id Select outerOrder 

我认为以下工作,SQL虽然丑陋:

 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 

这有用吗?

  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 

嗨,这可以很容易地工作……

而不是IQueryable

Dim orders As IQueryable(Of Order) = db.Orders

使用列表

 Dim orders as List(of Order) = db.Orders.ToList()