【问题标题】:LINQ: Dynamic predicate builder issueLINQ:动态谓词构建器问题
【发布时间】:2013-02-02 07:14:47
【问题描述】:

我正在尝试创建一个帮助类来轻松构建动态 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 分组表达式添加到原始谓词构建器时,您会得到 ​​p>

参数“f”未绑定到指定的 LINQ to Entities 查询表达式。

由于某种原因,我似乎无法创建嵌套表达式。 如果您将代码放在使用示例中执行查询的位置上方,则它可以工作(在制作一些 mods 之后)。

更新解决方案:

带星号的行需要更改为 Return predicate.And(inner.Expand)

【问题讨论】:

  • 感谢亚伦的提示。想要回答以便我接受吗?
  • 完成 - 很高兴我能提供帮助。顺便说一下,Visual Basic 实现是什么样的?为了后代的利益,您可以编辑您的问题以包含此内容:D

标签: linq entity-framework dynamic predicate predicatebuilder


【解决方案1】:

我不是 Visual Basic 人员,但在 C# 实现中,我认为您可能需要根据 albahari.com/nutshell/predicatebuilder.aspx 将 AsExpandable() 添加到查询中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多