我意识到SQL Server无法有效地处理一些基本的SQL查询,例如:
SELECT TOP (1) [t0].[Id], [t0].[L1], [t0].[L2], [t0].[Value]
FROM [Foos] AS [t0]
INNER JOIN [Lookup1] AS [t1] ON [t1].[Id] = [t0].[L2]
INNER JOIN [Lookup2] AS [t2] ON [t2].[Id] = [t0].[L1]
WHERE ([t1].[Name] = 'a') AND ([t2].[Name] = 'b')
ORDER BY [t0].[Value]
从LINQ表达式生成:
// query 1
Foos
.Where(f => f.Lookup1.Name == "a" && f.Lookup2.Name == "b")
.OrderBy(f => f.Value)
.Take(1)
架构定义有问题“Index over multiple lookup tables in SQL Server”。答案中的@Hoots显示SQL查询必须如下所示:
SELECT TOP (1) [t0].[Id], [t0].[L1], [t0].[L2], [t0].[Value]
FROM [Foos] AS [t0]
CROSS JOIN (
SELECT TOP (1) [t1].[Id], [t2].[Id] AS [Id2]
FROM [Lookup1] AS [t1], [Lookup2] AS [t2]
WHERE ([t1].[Name] = 'a') AND ([t2].[Name] = 'b')
) AS [t3]
WHERE ([t0].[L1] = [t3].[Id]) AND ([t0].[L2] = [t3].[Id2])
ORDER BY [t0].[Value] DESC
可以从以下LINQ表达式生成:
// query 2
(from f in Foos
from l in (
from l1 in Lookup1s
from l2 in Lookup2s
where l1.Name == "a"
&& l2.Name == "b"
select new { L1 = l1.Id, L2 = l2.Id }).Take(1)
where f.L1 == l.L1 && f.L2 == l.L2
orderby f.Value descending
select f).Take(1)
我的问题是如何自动将查询1重写为查询2?所以我可以通过多个步骤撰写查询:
void Do()
{
var x = ListFoos("a", "b").OrderBy(f => f.Value).Take(2);
// ...
}
IQueryable<Foos> ListFoos(string l1, string l2)
{
var foos = Foos.AsQueryable();
if (l1 != null)
foos = foos.Where(f => f.Lookup1.Name == l1);
if (l2 != null)
foos = foos.Where(f => f.Lookup2.Name == l2);
return foos;
}
有人已经完成了吗?是否有一个简化任务的库?
澄清:
生成的IQueryable<>
表达式被转换为SQL语句无法有效评估的SQL语句。所以我需要将表达式转换为一个表达式,该表达式被转换为SQL Server的更好的SQL语句。
我认为我不是第一个遇到此问题的人。 LINQ是一个较长的时间,SQL语句非常基本,因此其他开发人员可能已经使用SQL Server解决了这个问题。
答案 0 :(得分:0)
我不是100%肯定我知道你要求的是什么,但如果我是对的,你应该看看PredicateBuilder。这非常有用。链接到这里:
http://www.albahari.com/nutshell/predicatebuilder.aspx
这是LinqKit的一部分:
http://www.albahari.com/nutshell/linqkit.aspx
以及有关如何使用的一些信息:
How does PredicateBuilder work
它基本上可以让你做这样的事情:
var predicate = PredicateBuilder.True<Foo>();
if (l1 != null)
predicate = predicate.And(f => f.Lookup1.Name == l1);
if (l2 != null)
predicate = predicate.Or(f => f.Lookup2.Name == l2);
return Foos.Where(predicate);
请注意以上内容来自内存..我没有测试过这个...所以可能会有一些错别字......