当前位置: 首页 > 工具软件 > compiled > 使用案例 >

理解LINQ预编译查询(Compiled LINQ)

谷梁昊空
2023-12-01

从上一篇NHibernate与Entity Framework性能比较中可以看出来LINQ预编译查询可以大大提高性能。本文对预编译查询做简单介绍。 

首先了解什么是

匿名方法(anonymous function)和Func<>

 

 

1. 命名方法,匿名方法和Lambda表达式

在C#2.0之前,对委托赋值的唯一方式是通过的命名方法。C#2.0引入匿名方法以内联(in-line)方式使之变得直观和方便,而且匿名方法可以省略参数列表,可以将匿名方法转换为不同签名的委托。

C#3.0中Lambda表达式的语法跟匿名方法的非常相似,可用于构建委托或者LINQ表达式(Expression)。后面的例子中都会使用Lambda表达式对委托赋值。

class Test
{
delegate void TestDelegate(string s);
static void M(string s)
{
Console.WriteLine(s);
}

static void Main(string[] args)
{
// Original delegate syntax required initialization with a named method.
TestDelegate testDelA = new TestDelegate(M);

// C# 2.0: A delegate can be initialized with inline code, called an "anonymous method." This
// method takes a string as an input parameter.
TestDelegate testDelB = delegate(string s) { Console.WriteLine(s); };

// C# 3.0. A delegate can be initialized with a lambda expression. The lambda also takes a string
// as an input parameter (x). The type of x is inferred by the compiler.
TestDelegate testDelC = (x) => { Console.WriteLine(x); };
// Invoke the delegates.
testDelA("Hello. My name is M and I write lines.");
testDelB("That's nothing. I'm anonymous and ");
testDelC("I'm a famous author.");
}
}

2. Linq.Expression 和 Func<>

Linq.Expression就是LINQ表达式,继承Linq.Expressions.LambdaExpression

Func<>是一种委托,在LINQ中Func<>代表对应LINQ表达式的委托。

Linq表达式要变成可执行的代码(不是指SQL,而是指C#代码), 需要将Expression编译Func<>。我们通过一下代码来测试

//此时sqrExpression只是一个Expression,并不能执行
Expression<Func<double, double>> sqrExpression = (x => x * x);

//Compile成可执行的Func<>
Func<double, double> sqr = sqrExpression.Compile();

Console.Write(sqr(3));

3. 预编译LINQ

Compile是一步耗时的操作,在执行普通Linq查询的时候,每执行一次都自动Compile,即使同样的查询(参数可能不一样)已经被执行过多次。

EF对此有缓存机制,在同一个context内会将compile后的结果缓存起来,但是在一般场景下使用的都是短生命周期(short-life)的context,此缓存的作用是杯水车薪。

 //普通Linq查询       
public IList<Product> SearchByName(string name)
{
using (NorthWindEntities ctx = new NorthWindEntities())
{
      //每次执行是都会自动compile
return ctx.Products.Where(o => o.ProductName.Contains(name.Trim())).ToList();
}
}

 

对此我们可以考虑将编译后的结果(Func<>)保存起来以重用

private static Func<NorthWindEntities, string, IQueryable<Product>> searchByNameQuery =
CompiledQuery.Compile<NorthWindEntities, string, IQueryable<Product>>
((NorthWindEntities ctx, string name) => ctx.Products.Where(o => o.ProductName.Contains(name.Trim())));
public IList<Product> SearchByNameCompiled(string name)
{
using (NorthWindEntities ctx = new NorthWindEntities())
{
return searchByNameQuery(ctx, name).ToList();
}
}

上面的例子我们把编译后的Func<>放到一个static变量中,这样可以保证全局范围内只需要compile一次。当然也可以在此基础上再做改进,比如Lazy-load Singleton。

为了提高程序性能,你几乎可以在所用地方都使用预编译LINQ,当然查询语句越复杂的时候效果就越明显。

转载于:https://www.cnblogs.com/hiteddy/archive/2011/09/21/understanding_Compiled_LINQ.html

 类似资料: