上个月当我的本地 .NET 用户组的演示者正在课堂上写 LINQ 查询时,我问他 ,“以前没有 LINQ 的时候,我们是怎么过的”?他回答说,“真是难以想象” 。
这是真的。自从 2008 年 LINQ 被引入 Visual Studio 后,它对我们在 Microsoft .NET Framework 中的编程方式产生了如此 重大的影响。与 Visual Basic 和 C# 中引入的许多新的语言功能相结合,LINQ 可以前后一致地解决查 询内存中对象和数据来源的问题。
LINQ 具备将形状随机的数据投影到匿名类型的功能,这种功能既有好的一面 ,也有不好的一面。如果您只需要获取数据的特定视图,而不必为此一次性的类 型声明新类,匿名类型是一个不错的解决方案。LINQ 的投影和匿名类型的确是把 我们宠坏了。那么,为什么我说,它们也有不好的一面呢?
如果您曾经将 LINQ 投影用于需要将数据返回另一方法的某种方法,或者更糟 糕,将 LINQ 投影用在 Windows Communication Foundation (WCF) 服务操作中 ,对此您可能会有所了解。
原因即在于匿名类型是一次性类型,它们没有声明,只有创建它们的方法可以 理解它们。如果您写了一个返回一列匿名类型的查询,因为没有办法表达“匿名 类型”,所以没有办法定义某个方法参数,说:“我将返回一列...”。
以下是一个采用简单投影的 LINQ to Entities 查询:
var custQuery = from c in context.Customers
select new {c.CustomerID, Name=c.LastName.Trim() +
", " + c.FirstName};
在运行时,custQuery 变量将实际成为某个 ObjectQuery<<>f__AnonymousType0<int,string>>。
有了 var(以及 Visual Basic Dim 的替代使用)我们不再需要找到这种非类 型的表达方式。
如果您想从某个方法返回该查询的结果,唯一合理的解决方案是创建代表要返 回的类型的类。不过,这样做,提供匿名类型将毫无意义。现在您必须写更多的 代码,定义类,还可能需要定义容纳新类的新项目,并确保使用这些类的程序集 能访问到它们等等。
最近,数据服务又给出了一道难题。为了对数据进行投影,您必须在服务中创 建自定义的操作,执行自己的查询,然后返回某一预先定义的、可以为客户端理 解的类。
在您处理服务时,很多情况下您都希望在无需通过线路移动大规模类型的情况 下,处理数据的特定视图。
为了满足这一临时性要求,除了在您的域中创建额外的类型之外,您还有更多 的选择。
WCF 数据服务中的新投影功能
.NET Framework 3.5 SP1 的数据服务更新为 WCF 数据服务引入了少数几个强 大的功能,这也是 .NET Framework 4 的组成部分。这些功能中就有针对数据服 务在查询中使用投影的功能。强烈建议您查看 WCF 数据服务团队的博客帖子 (blogs.msdn.com/astoriateam/archive/2010/01/27/data-services-update- for-net-3-5-sp1-available-for-download.aspx),以了解这次更新的所有新功 能。
数据服务 URI 语法中添加了 $select 运算符。它允许使用属性甚至是导航属 性投影。
下面简单举例说明了随 SalesOrderHeaders 导航属性获取客户的几个标量属 性的投影:
http://localhost /DataService.svc/Customers(609)
$select=CustomerID,LastName,FirstName,SalesOrderHeaders&$expand=
SalesOrderHeaders