我为LINQ to OBJECTS编写了以下扩展方法,它完全符合我的要求,但我无法使用LINQ to SQL。
<Extension()> Public Function ThenByLike(Of T As Class)(ByVal items As IOrderedEnumerable(Of T), PropertySelector As Func(Of T, String), Ascending As Boolean, ParamArray Searches As String()) As IOrderedEnumerable(Of T)
Searches = If(Searches, {})
If Searches.Count > 0 Then
For Each t In Searches
For Each exp In {
Function(x) PropertySelector(x) = t,
Function(x) PropertySelector(x).StartsWith(t),
Function(x) PropertySelector(x).Contains(t),
Function(x) PropertySelector(x).EndsWith(t)
}
If Ascending Then
items = items.ThenByDescending(exp)
Else
items = items.ThenBy(exp)
End If
Next
Next
End If
Return items
End Function
我得到以下异常:
方法'System.Object DynamicInvoke(System.Object [])'不受支持 转换为SQL。
要使该方法与LINQ to SQL兼容,我需要做什么?
答案 0 :(得分:0)
我找到了解决方案。我需要将该函数转换为以下代码,以获取在SQL Server上运行的有效SQL查询。
<Extension()> Public Function ThenByLike(Of T)(ByVal items As IOrderedQueryable(Of T), Searches As String(), SortProperty As Expression(Of Func(Of T, String)), Optional Ascending As Boolean = True) As IOrderedQueryable(Of T)
Dim type = GetType(T)
Searches = If(Searches, {})
For Each t In Searches
Dim mem As MemberExpression = SortProperty.Body
Dim [property] = mem.Member
Dim parameter = SortProperty.Parameters.First
Dim propertyAccess = Expression.MakeMemberAccess(parameter, [property])
Dim orderByExp = Expression.Lambda(propertyAccess, parameter)
Dim tests As MethodCallExpression() = {
Expression.Call(propertyAccess, startsWithMethod, Expression.Constant(t)),
Expression.Call(propertyAccess, containsMethod, Expression.Constant(t)),
Expression.Call(propertyAccess, endsWithMethod, Expression.Constant(t))
}
For Each exp In tests
Dim nv = Expression.Lambda(Of Func(Of T, Boolean))(exp, parameter)
If Ascending Then
items = items.ThenByDescending(nv)
Else
items = items.ThenBy(nv)
End If
Next
Next
Return items
End Function
Private containsMethod As MethodInfo = GetType(String).GetMethod("Contains")
Private endsWithMethod As MethodInfo = GetType(String).GetMethod("EndsWith", {GetType(String)})
Private startsWithMethod As MethodInfo = GetType(String).GetMethod("StartsWith", {GetType(String)})