我正在尝试创建一个帮助程序类来轻松构建动态LINQ查询。代码是这篇优秀CodeProject文章的严格修改版本:http://www.codeproject.com/Articles/493917/Dynamic-Querying-with-LINQ-to-Entities-and-Express,它在这里使用PredicateBuilder:http://www.albahari.com/nutshell/predicatebuilder.aspx
我仍然在清理代码,所以变量名称目前都是垃圾,看不到一条评论。
用法
Dim conditions As New List(Of Condition)
With conditions
.Add(New Condition With {.Field = "EatsPeople", .Operator = "Equals", .Value = False})
.Add(New Condition With {.Field = "Name", .Operator = "Equals", .Value = "Adric"})
.Add(New Condition With {.Field = "Description", .Operator = "Contains", .Value = "ugly"})
End With
Dim predicate = BuildPredicate(conditions)
Dim tester = data.Monsters.AsExpandable.Where(predicate).ToList
实体
Public Class Monster
Public Property EatsPeople As Boolean
Public Property Name As String
Public Property Description As String
End Class
搜索存储空间:
Public Class Condition
Public Property Field As String
Public Property [Operator] As String
Public Property Value As Object
End Class
方法
Public Function BuildPredicate(conditions As List(Of Condition)) As Expression(Of Func(Of Monster, Boolean))
Dim predicate = PredicateBuilder.True(Of Monster)()
For Each c In conditions
Dim dbFieldName = c.Field
Dim dbType = GetType(Monster)
Dim dbFieldMemberInfo = dbType.GetMember(dbFieldName, BindingFlags.IgnoreCase Or BindingFlags.Public Or BindingFlags.Instance).Single()
predicate = BuildExpression(c, dbType, dbFieldMemberInfo, predicate)
Next
Return predicate
End Function
Private Function CreateLambda(value As Object, method As MethodInfo, ByVal dbType As Type, ByVal dbFieldMemberInfo As MemberInfo) As Expression(Of Func(Of Monster, Boolean))
Dim dbTypeParameter = Expression.Parameter(dbType, "x")
Dim dbFieldMember = Expression.MakeMemberAccess(dbTypeParameter, dbFieldMemberInfo)
Dim criterionConstant = New Expression() {Expression.Constant(value)}
Dim containsCall = Expression.Call(dbFieldMember, method, criterionConstant)
Return TryCast(Expression.Lambda(containsCall, dbTypeParameter), Expression(Of Func(Of Monster, Boolean)))
End Function
问题方法
Private Function BuildExpression(condition As Condition, ByVal dbType As Type, ByVal dbFieldMemberInfo As MemberInfo, ByVal predicate As Expression(Of Func(Of Monster, Boolean))) As Expression(Of Func(Of Monster, Boolean))
Dim type = condition.Value.GetType
Dim method As MethodInfo = type.GetMethod(condition.Operator, BindingFlags.Instance Or BindingFlags.Public, Nothing, {type}, Nothing)
If type = GetType(String) Then
If condition.Value.ToString.Contains(",") = True Then
Dim inner = PredicateBuilder.False(Of Product)()
For Each v In condition.Value.ToString.Split(",")
inner = inner.Or(CreateLambda(v, method, dbType, dbFieldMemberInfo))
Next
*****Return predicate.And(inner)*****
End If
End If
Return predicate.And(CreateLambda(condition.Value, method, dbType, dbFieldMemberInfo))
End Function
有什么问题?
最后一个方法中由五个星号包围的行是问题所在。
将OR分组表达式添加到原始谓词构建器时,您将获得
参数'f'未绑定在指定的LINQ to Entities中 查询表达式。
出于某种原因,我似乎无法创建嵌套表达式。 如果你把代码放在使用样本中执行查询的上面,那么它就可以了(在做了一些mod之后)。
使用解决方案进行更新:
带星号的行需要更改为
Return predicate.And(inner.Expand)
答案 0 :(得分:0)
我不是Visual Basic人员,但在C#实现中,我认为您可能需要根据albahari.com/nutshell/predicatebuilder.aspx将AsExpandable()添加到您的查询中。