在LINQ to SQL中使用Translate方法以及修改查询用SQL2010-11-27 博客园 老赵目前LINQ to SQL的资料不多——老赵的意思是,目前能找到的资 料都难以摆脱“官方用法”的“阴影”。LINQ to SQL最 权威的资料自然是MSDN,但是MSDN中的文档说明和实例总是显得“大开大 阖”,依旧有清晰的“官方”烙印——这简直是一 定的。不过从按照过往的经验,在某些时候如果不按照微软划定的道道来走,可 能就会发现别样的风景。老赵在最近的项目中使用了LINQ to SQL作为数据层的基础,在LINQ to SQL开发方面积累了一定经验,也总结出了一些官方文档上并 未提及的有用做法,特此和大家分享。言归正传,我们先看一个简单的 例子。

Item实体对应Item表,每个Item拥有一些评论,也就是ItemComment。 Item实体中有一个Comments属性,是ItemComment实体的集合。这个例子将会使 用这个再简单不过的模型。为用户显示他的Item列表是非常常见的需求 ,如果使用LINQ to SQL来获取Item的话,我们可能会这么做:
public List<Item> GetItemsForListing(int ownerId)
{
ItemDataContext dataContext = new ItemDataContext ();
var query = from item in dataContext.Items
where item.UserID == ownerId
orderby item.CreateTime descending
select item;
return query.ToList();
}
这么做自然可以实现我们想要的功 能,这的确没错。但是这种做法有个很常见的问题,那就是可能会获得太多不需 要的数据。一个Item数据量最大的是Introduction字段,而显示列表的时候我们 是不需要显示它的。如果我们在获取Item列表时把Introduction一起获得的话, 那么应用服务器和数据库服务器之间的数据通信量将会成百甚至上千地增长了。 因此我们在面向此类需求的话,都会忽略每个Item对象的Introduction字段。那 么我们该怎么做呢?对LINQ有简单了解的朋友们可能会想到这么做:
public List<Item> GetItemsForListing(int ownerId)
{
ItemDataContext dataContext = new ItemDataContext ();
var query = from item in dataContext.Items
where item.UserID == ownerId
orderby item.CreateTime descending
select new Item
{
ItemID = item.ItemID,
Title = item.Title,
UserID = item.UserID,
CreateTime = item.CreateTime
};
return query.ToList ();
}
这个做法很直观,利用了C# 3.0中的Object Initializer 特性。编译通过了,理应没有错,可是在运行时却抛出了 NotSupportedException:“Explicit construction of entity type "Demo.Item" in query is not allowed.”,意思就是不能在 LINQ to SQL中显式构造Demo.Item对象。事实上在RTM之前的版本中,以 上的语句是能运行通过的——我是指通过,不是正确。LINQ to SQL 在RTM之前的版本有个Bug,如果在查询中显式构造一个实体的话,在某些情况下 会得到一系列完全相同的对象。很可惜这个Bug我只在资料中看到过,而在RTM版 本的LINQ to SQL中这个Bug已经被修补了,确切地说是绕过了。直接抛出异常不 失为一种“解决问题”的办法,虽然这实际上是去除了一个功能 ——没有功能自然不会有Bug,就像没有头就不会头痛了一个道理。但是我们还得做,难道我们只能自己SQL语句了吗?