在LINQ to SQL中使用Translate方法以及修改查询用SQL
摘要:老赵在最近的项目中使用了LINQ to SQL作为数据层的基础,在LINQ to SQL开发方面积累了一定经验,也总结出了一些官方文档上并未提及的有用做法,特此和大家分享。
[1] 引入[2] 使用Translate方法1
[3] 使用Translate方法2
[4] 改变LINQ to SQL所执行的SQL语句
[5] 扩展所受的限制
以上扩展所受限制
以上的扩展并非无可挑剔。由于Translate方法的特点,此类做法都无法充分发挥LINQ to SQL查询的所有能力——那就是所谓的“LoadWith”能力。
在LINQ to SQL中,默认会使用延迟加载,然后在必要的时候才会再去数据库进行查询。这个做法有时候会降低系统性能,例如:
List<Item> itemList = GetItems(1); foreach (Item item in itemList) { foreach (ItemComment comment in item.Comments) { Console.WriteLine(comment.Content); } }
这种做法的性能很低,因为默认情况下每个Item对象的ItemComment集合不会被同时查询出来,而是会等到内层的foreach循环执行时再次查询数据库。为了避免不合适的Lazy Load降低性能,LINQ to SQL提供了DataLoadOptions机制进行控制:
public static List<Item> GetItems(int ownerId) { ItemDataContext dataContext = new ItemDataContext(); DataLoadOptions loadOptions = new DataLoadOptions(); loadOptions.LoadWith<Item>(item => item.Comments); dataContext.LoadOptions = loadOptions; var query = from item in dataContext.Items where item.UserID == ownerId orderby item.CreateTime descending select item; return query.ToList(); }
当我们为DataContext对象设置了LoadOptions并且指明了“Load With”关系,LINQ to SQL就会根据要求查询数据库——在上面的例子中,它将生成如下的SQL语句:
SELECT [t0].[ItemID], [t0].[Title], [t0].[Introduction], [t0].[UserID], [t0].[CreateTime], [t1].[ItemCommentID], [t1].[ItemID] AS [ItemID2], [t1].[Content], [t1].[UserID], [t1].[CreateTime] AS [CreateTime2], ( SELECT COUNT(*) FROM [dbo].[ItemComment] AS [t2] WHERE [t2].[ItemID] = [t0].[ItemID] ) AS [value] FROM [dbo].[Item] AS [t0] LEFT OUTER JOIN [dbo].[ItemComment] AS [t1] ON [t1].[ItemID] = [t0].[ItemID] WHERE [t0].[UserID] = @p0 ORDER BY [t0].[CreateTime] DESC, [t0].[ItemID], [t1].[ItemCommentID]
相信大家已经了解Translate方法为何无法充分发挥LINQ to SQL的能力了。那么我们又该如何解决这个问题呢?如果您希望同时使用本文类似的扩展和Load With能力,可能就需要通过查询两次数据库并加以组合的方式来生成对象了——虽然查询了两次,但总比查询100次的性能要高。