如何以最佳方式合并LINQ-to-SQL查询

时间:2012-03-13 18:15:04

标签: .net vb.net linq-to-sql

我已经解决了我的问题,但是因为我之前已经尝试过但未能解决它,这次我花了很多功夫,我想发布问题,如果没有人有更好的答案,我的解决方案所以我不会忘记将来如何做到这一点,并帮助其他人面临类似的挑战。我的挑战是:

我有一个函数用于过滤选项列表,只返回批量跟踪的选项,并且在适用的情况下,也只显示与指定模式匹配的项目:

  Private Shared Function FilterResultsLot(ByVal source As IQueryable(Of Item), _
     ByVal itemCode As String) As IQueryable(Of Item)
     If HasFilter(itemCode, True) Then
        Return From row In source Where row.ItemDetail.IsLotTraced AndAlso _
               row.ItemCode.ToLower() Like itemCode.ToLower()
     Else
        Return From row In source Where row.ItemDetail.IsLotTraced
     End If
  End Function

出现了另一个要求,我希望能够将批次跟踪的标准推广到一般过滤器中,所以我创建了这个函数:

  Private Shared Function FilterResults(source As IQueryable(Of Item), _
     itemCode As String, filter As Func(Of Item, Boolean)) As IQueryable(Of Item)
     Dim predicate As Func(Of Item, Boolean)
     If HasFilter(itemCode, True) Then
        predicate = Function(row) row.ItemCode.ToLower() Like itemCode.ToLower() AndAlso filter.Invoke(row)
     Else
        predicate = filter
     End If
     Return source.Where(predicate).AsQueryable()
  End Function

该函数通过LINQ-to-SQL工作,但它失去了重要的优化。而第一个函数是以以下结尾执行SQL查询:

FROM [dbo].[OITM] AS [t0]
LEFT OUTER JOIN [dbo].[FSE_ItemDetail] AS [t1] ON [t1].[ItemCode] = [t0].[ItemCode]
WHERE ([t1].[IsLotTraced] = 1) AND (LOWER([t0].[ItemCode]) LIKE @p0 ESCAPE ''~'')

第二个会执行带有这些结尾的多个SQL查询(可能还有更多):

FROM [dbo].[OITM] AS [t0]

FROM [dbo].[FSE_ItemDetail] AS [t0]
WHERE [t0].[ItemCode] = @p0',N'@p0 nvarchar(4000)',@p0=N'BF-BIKE'

FROM [dbo].[FSE_ItemDetail] AS [t0]
WHERE [t0].[ItemCode] = @p0',N'@p0 nvarchar(4000)',@p0=N'BF-BIKE-ITEM'

所以问题是如何在不调用Invoke或AsQueryable的情况下将LINQ-to-SQL委托表达式组合成一个,或者不失去最佳执行。

1 个答案:

答案 0 :(得分:1)

这是我目前的解决方案。如果您有任何问题,请发表评论或提供更好的解决方案:

  Private Shared Function FilterResults(source As IQueryable(Of Item), itemCode As String, filter As Expressions.Expression(Of Func(Of Item, Boolean))) As IQueryable(Of Item)
     If HasFilter(itemCode, True) Then
        Return Queryable.Where(Queryable.Where(source, Function(row) row.ItemCode.ToLower() Like itemCode.ToLower()), filter)
     Else
        Return Queryable.Where(source, filter)
     End If
  End Function

修改

在使用它之后,我更喜欢这种语法的简化/替代:

Return Queryable.Where(Queryable.Where(source, _
   Function(row) row.ItemCode.ToLower() Like itemCode.ToLower()), filter)

我的偏好是:

Return Queryable.Where(From row in source _
   Where row.ItemCode.ToUpper() Like itemCode.ToUpper(), filter)

(我还建议ToUpper而不是ToLower在区分大小写的服务器上强制不区分大小写的匹配,因为我听说UPPER更适合于此。)