技术开发 频道

LINQ 未满


  当然,LINQ 正式推出的时候,肯定会附带一个代码生成器,用以从数据库结构生成相应的 class,而这些 class 如果完全不需要修改的话,倒也问题不大就是了。

  LINQ 本身,和 lambda 表达式有很大的关系。本来,如果 lambda 表达式只是匿名方法的更简化写法的话,意义倒也不大,不过,在 .Net 3.0 中,对于 lambda 表达式提供了一种表达式树的处理方式:
1. Expression<Func<int, bool>> filter = n => n < 5; 2. 3. BinaryExpression body = (BinaryExpression)filter.Body; 4. ParameterExpression left = (ParameterExpression)body.Left; 5. ConstantExpression right = (ConstantExpression)body.Right; 6. 7. Console.WriteLine("{0} {1} {2}", 8. left.Name, body.NodeType, right.Value);
  以上代码的运行结果是: n LT 5

  最神奇的地方是,n < 5 本来应该返回一个 bool 值,但是现在,返回给我们的却是一颗分析树,而对于这个分析结果怎么再处理,就交给我们来决定了。换句话说,C# 帮我们做语法检查和语法分析,把分析结果给我们,从而使我们可以创建内嵌于 C# 内部的子语言,可以用于创建DSL——领域特定语言了。

  说到这里,不妨简单说一下 db4o 这个对象数据库系统。它的原生查询方式很有意思:
1. IList<Student> students = database.Query<Student> ( 2. delegate(Student student){ 3. return student.Age < 20 4. && student.Name.Contains("f"); 5. });
  如上所示,db4o 用一个匿名方法来完成查询条件的设置,这种方式包含 IDE 的智能提示,完善的语法检查等优点,而且,因为它本身只是 .Net (或 Java)的一个类库,所以,没有其他数据库的进程间通讯的开销,另外,它是对象数据库,所以也没有 O/R Mapping 的开销,这都使得这种所谓的原生查询得以很好的实现。

  不过,问题出在索引上。如上的例子,我们可以理解,这是数据库对于表中所有数据进行遍历,并且回调这个代理函数,对于需要进程间通讯的数据库,这种开销是不可接受的,不过对于 db4o 来说,只是函数调用的开销而已。但是,对于有索引的字段,数据库是应该使用二分法查找的,但是在这种原生查询中,数据库事实上不知道用户要查询哪个字段,以及使用哪个值进行什么样的比较,所以也无法利用二分法提供给这个代理函数期望的值,而只能完全遍历。

  所以,db4o 提供了另一种语法,类似 Sql 子语句或者说是有些类似 ORM 的方式来进行有索引字段的查询,使用这种方式的话,就可以使用到索引了:
1. Query query = database.Query(); 2. query.Constrain(typeof(Student)); 3. query.Descend("age").Constrain(20).Smaller(); 4. IList students = query.Execute();
  不过,这种方式又丧失了原生查询中,IDE 的智能提示和语法检查之类的优点,而且,一种数据库提供两种语法的查询,而且相差这么大,是有些让人郁闷的。
0
相关文章