1

動的LINQクエリを簡単に構築するためのヘルパークラスを作成しようとしています。コードは、この優れたCodeProject記事の大幅に変更されたバージョンです:http://www.codeproject.com/Articles/493917/Dynamic-Querying-with-LINQ-to-Entities-and-ExpressここでPredicateBuilderを使用します:http:// www.albahari.com/nutshell/predicatebuilder.aspx

私はまだコードをクリーンアップしている最中なので、変数名は現時点ではごちゃごちゃしていて、コメントは1つも見えません。

使用法

    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

何が問題ですか?

5つのアスタリスクで囲まれた最後のメソッドの行が問題です。

ORグループ化された式を元の述語ビルダーに追加すると、次のようになります。

パラメーター'f'は、指定されたLINQtoEntitiesクエリ式にバインドされていませんでした。

どういうわけか、ネストされた式を作成できないようです。使用法のサンプルでクエリが実行される場所に上記のコードを配置すると、(いくつかのmodを作成した後に)機能します。

ソリューションで更新:

アスタリスクの付いた行を次のように変更する必要があります Return predicate.And(inner.Expand)

4

1 に答える 1

0

私は Visual Basic の専門家ではありませんが、C# の実装では、albahari.com/nutshell/predicatebuilder.aspx に従ってクエリに AsExpandable() を追加する必要があると思います。

于 2013-02-03T02:55:50.510 に答える