Linq to Entities Group By(OUTER APPLY)“oracle 11.2.0.3.0不支持申请”

我在下面有代码示例查询产品列表。

var productResults = Products.Where((p) => refFilterSequence.Contains(p.Ref)) .GroupBy(g => g.Code, (key, g) => g.OrderBy(whp => whp.Ref).First()).ToList(); 

这完全按预期工作,并在使用内存集合时返回我想要的4行,但是在针对Oracle数据库运行时:

 .GroupBy(g => g.Code, (key, g) => g.OrderBy(whp => whp.Ref).First()) 

这会抛出一个错误,说我应该使用Oracle数据库不支持的FirstOrDefault 。 错误oracle 11.2.0.3.0不支持apply thrown。 谷歌在CodePlex上揭示了这一点: https : //entityframework.codeplex.com/workitem/910 。

使用以下二进制文件时会发生这种情况:

  • EntityFramework 6.0.0.0
  • Oracle.ManagedDataAccess 4.121.2.0
  • Oracle.ManagedDataAccess.EntityFramework 6.121.2.0
  • .Net Framework 4.5.1

该数据库是Oracle 11.2.0.3.0数据库。

生成的sql使用OUTER APPLY(见下图),但11.2.0.3.0版本的Oracle不支持,那么为什么EF / Oracle.ManagedDataAccess会尝试使用它呢? 有没有办法告诉EF不要使用APPLY关键字?

SQL

下面的页面显示在Oracle 12c第1版中添加了APPLY支持,但我无法更新所有数据库只是为了使GROUP BY工作。 http://www.oracle.com/technetwork/database/windows/newfeatures-084113.html

看来这是一个已知问题( SqlClient for Entity Framework中的已知问题 ):

以下是可能导致输出查询中存在CROSS APPLY和/或OUTER APPLY运算符的一些典型方案:

  • LINQ查询使用接受元素选择器的分组方法。

在我开始创建视图之前(我必须在几个数据库上创建视图),任何人都可以看到另一个解决方案吗?

对于任何感兴趣的人来说,针对这个数据库版本执行我想做的SQL看起来如下所示:

 select * from ( select RANK() OVER (PARTITION BY sm.product ORDER BY refs.map) ranking, sm.* from schema.table sm, ( select 'R9' ref, 0 map from dual union all select 'R1' ref, 1 map from dual union all select 'R6' ref, 2 map from dual ) refs where sm.ref= refs.ref ) stock where ranking = 1 

代码最终将在传递给Web API中的OData控制器的服务类中。 下面的示例使用演示数据,真实数据库有700,000条记录,因此我希望避免执行查询并让OData处理页面限制和进一步过滤。

 using System; using System.Collections.Generic; using System.Linq; namespace DemoApp { class Program { public class Product { public string Ref { get; set; } public string Code { get; set; } public int Quantity { get; set; } } //demo data static readonly List Products = new List { new Product { Ref = "B2", Code = "ITEM1", Quantity = 1}, new Product { Ref = "R1", Code = "ITEM1", Quantity = 2}, new Product { Ref = "R9", Code = "ITEM1", Quantity = 3}, new Product { Ref = "R9", Code = "ITEM2", Quantity = 4}, new Product { Ref = "R6", Code = "ITEM2", Quantity = 5}, new Product { Ref = "B2", Code = "ITEM3", Quantity = 6}, new Product { Ref = "R1", Code = "ITEM3", Quantity = 7}, new Product { Ref = "R9", Code = "ITEM3", Quantity = 8}, new Product { Ref = "B2", Code = "ITEM4", Quantity = 9}, new Product { Ref = "X3", Code = "ITEM4", Quantity = 10}, new Product { Ref = "B8", Code = "ITEM5", Quantity = 10}, new Product { Ref = "R6", Code = "ITEM5", Quantity = 12}, new Product { Ref = "M2", Code = "ITEM5", Quantity = 13}, new Product { Ref = "R1", Code = "ITEM5", Quantity = 14}, }; static void Main(string[] args) { // this array is of variable length, and will not always contain 3 items. var refFilterSequence = new List {"R9", "R1", "R6"}; var results = GetProductsForODataProcessing(refFilterSequence); // some further filtering may occur after the queryable is returned. // the actual implmentation is an OData Web API, so filters, expansions etc could be added. //results = results.Where(p => p.Quantity > 2); results.ToList().ForEach(p => Console.WriteLine("RANK:{0}\tREF:{1}\tCode:{2}\tQty:{3}", "?", p.Ref, p.Code, p.Quantity)); Console.ReadLine(); } static IQueryable GetProductsForODataProcessing(List filterSequence ) { var productResults = Products.Where((p) => filterSequence.Contains(p.Ref)) .GroupBy(g => g.Code, (key, g) => g.OrderBy(whp => whp.Ref).First()).AsQueryable(); return productResults; } } // Example Output // ....................... // REF:R1 Code:ITEM1 Qty:2 // REF:R6 Code:ITEM2 Qty:3 // REF:R1 Code:ITEM3 Qty:7 // REF:R1 Code:ITEM5 Qty:14 

因为你可以自己编写查询。 也许您可以使用它创建存储过程并从Entity Framework调用SP。

您可以尝试在GroupBy之前执行ToArray,因此它在内存中执行。 它不是最佳性能,但应该起作用。

  var productResults = Products.Where((p) => refFilterSequence.Contains(p.Ref)).ToArray() .GroupBy(g => g.Code, (key, g) => g.OrderBy(whp => whp.Ref).First()).ToList(); 

Oracle 11不支持APPLY。 但是,Oracle 12确实如此。