Выражения Linq с Linq to Entities

Я пытаюсь обернуть повторяющийся код в метод расширения, чтобы немного навести порядок.

Шаблон, которого я пытаюсь избежать, заключается в проверке того, является ли строка (обычно текстовое значение элемента управления) нулевой/пустой, и если это так, сравнение ее с помощью «Содержит» с полем в моих данных. Очевидно, что поле не жестко запрограммировано в моем расширении, равно как и тип объекта.

То, что у меня есть, отлично работает в Linq to Objects, но я получаю общую ошибку времени выполнения «LINQ to Entities не распознает метод System.String Invoke (GenericQueryHelper.Customer)», и этот метод не может быть переведен в выражение магазина». при использовании модели фреймворка сущностей.

Вот что у меня есть:

<System.Runtime.CompilerServices.Extension()>
Public Function CompareAndFilter(Of T)(source As System.Linq.IQueryable(Of T), expressionField As System.Linq.Expressions.Expression(Of System.Func(Of T, String)), compareTo As String)
    If String.IsNullOrEmpty(compareTo) Then
        Return source
    Else
        Dim compiledField As System.Func(Of T, String) = expressionField.Compile()
        Return source.Where(Function(x) compiledField.Invoke(x).Contains(compareTo))
    End If
End Function

И я также пробовал:

<System.Runtime.CompilerServices.Extension()>
Public Function CompareAndFilter(Of T)(source As System.Linq.IQueryable(Of T), expressionField As System.Func(Of T, String), compareTo As String)
    If String.IsNullOrEmpty(compareTo) Then
        Return source
    Else
        Return source.Where(Function(x) expressionField.Invoke(x).Contains(compareTo))
    End If
End Function

С одинаковым исходом...

Во-первых, это вообще возможно? Я хочу, чтобы мое использование выглядело примерно так:

Dim results = repository.Customers.CompareAndFilter(Function(c) c.FirstName, searchText)

Мне действительно нужно, чтобы это работало с базой данных SQL, так как это фильтрует результаты, поэтому я не хочу делать это в памяти. У кого какие мысли?


person RichardW1001    schedule 28.02.2012    source источник


Ответы (2)


Linq to entity не понимает, как вызвать делегата, ему нужно выражение для обработки SQL для генерации.

Следующее может быть в состоянии сделать то, что вам нужно:

<System.Runtime.CompilerServices.Extension()>
Public Function CompareAndFilter(Of T)(source As System.Linq.IQueryable(Of T), expressionField As System.Linq.Expressions.Expression(Of System.Func(Of T, String)), compareTo As String)
    If String.IsNullOrEmpty(compareTo) Then
        Return source
    Else
        Return source.GroupBy(expressionField)
            .Where(Function(g) g.Key.Contains(compareTo))
            .SelectMany(Function(g) g)
    End If
End Function

GroupBy используется для выбора поля, указанного expressionField, затем проверяется ключ и возвращаются элементы в каждой группе.

person Lukazoid    schedule 28.02.2012
comment
Никогда бы не подумал об этом за миллион лет! Работает шарм, хороший! - person RichardW1001; 29.02.2012

Да, это возможно, но для этого требуется выражение манипуляция. Вы можете либо проанализировать полученное выражение и построить новое выражение критерия самостоятельно или попросите LINQKit выполнить для вас обход дерева.

person StriplingWarrior    schedule 28.02.2012
comment
Хороший материал для чтения, спасибо! Возможно, вы только что ответили на целую кучу будущих вопросов! - person RichardW1001; 29.02.2012