我在下面有代码示例查询产品列表。
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不支持应用被抛出。谷歌在CodePlex上展示了这一点:https://entityframework.codeplex.com/workitem/910。
使用以下二进制文件时会发生这种情况:
该数据库是Oracle 11.2.0.3.0数据库。
生成的sql使用OUTER APPLY(见下图),Oracle 11.2.0.3.0版本不支持,那么为什么EF / Oracle.ManagedDataAccess会尝试使用它?有没有办法告诉EF不要使用APPLY关键字?
下面的页面显示在Oracle 12c第1版中添加了APPLY支持,但我无法更新所有数据库只是为了使GROUP BY工作。 http://www.oracle.com/technetwork/database/windows/newfeatures-084113.html
这似乎是一个已知问题(Known Issues in 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<Product> Products = new List<Product>
{
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<string> {"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<Product> GetProductsForODataProcessing(List<string> 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
答案 0 :(得分:1)
因为您可以自己编写查询。也许您可以使用它创建存储过程并从实体框架中调用SP。
答案 1 :(得分:0)
您可以尝试在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();
答案 2 :(得分:-2)
Oracle 11不支持APPLY。但是,Oracle 12确实如此。