Пользовательский IQueryProvider, который использует LinqToObjects

Я написал собственный класс IQueryProvider, который принимает выражение и анализирует его в базе данных SQL (. Я знаю, что мог бы использовать Linq2Sql, но есть некоторые необходимые мне модификации и настройки, которые, к сожалению, делают Linq2Sql непригодным ). Класс будет идентифицировать и делать что-то со свойствами, помеченными (, используя атрибуты ), но все, что не так. Я хотел бы иметь возможность передать выражение поставщику LinqToObject и позволить ему фильтровать результаты после.

Например,предположим, у меня есть следующее выражение linq:

var parents=Context.Parents
   .Where(parent=>parent.Name.Contains("T") && parent.Age>18);

Класс Parents — это настраиваемый класс, который реализует интерфейсы IQueryProvider и IQueryable, но для извлечения помечено только свойство Age, поэтому свойство Age будет обработано, а свойство Name игнорируется, поскольку оно не помечено. После того, как я закончу обработку свойства Age, я хотел бы передать все выражение в LinqToObjects для обработки и фильтрации, но я не знаю, как это сделать.

Н.Б. Нет необходимости удалять предложение Age выражения, потому что результат будет таким же даже после того, как я его обработаю, поэтому я всегда смогу отправить все выражение в LinqToObjects.

Я пробовал следующий код, но он не работает:

IEnumerator IEnumerable.GetEnumerator() {       
    if(this.expression != null && !this.isEnumerating) {
        this.isEnumerating = true;
        var queryable=this.ToList().AsQueryable();
        var query = queryable.Provider.CreateQuery(this.expression);
        return query.GetEnumerator();
    }
    return this;
}

this.isEnumerating — это просто логический флаг, установленный для предотвращения рекурсии.

this.expression содержит следующее:

{value(namespace.Parents`1[namespace.Child]).Where(parent => ((parent.Name.EndsWith("T") AndAlso parent.Name.StartsWith("M")) AndAlso (parent.Test > 0)))}

Когда я выполняю код, несмотря на преобразование результатов в список, он по-прежнему использует мой пользовательский класс для запроса. Итак, я решил, что, поскольку класс Parent находится в начале выражения, он все еще перенаправляет запрос обратно моему провайдеру, поэтому я попытался установить для this.expression значение Argument[1] вызова метода, чтобы оно было как таковое :

{parent => ((parent.Name.EndsWith("T") AndAlso parent.Name.StartsWith("M")) AndAlso (parent.Test > 0))}

. ] Что для меня больше похоже на это, однако всякий раз, когда я передаю это в функцию CreateQuery, я получаю эту ошибку «Выражение аргумента недопустимо».

Тип узла выражения теперь «Цитата», а не «Вызов», и метод имеет значение null. Я подозреваю, что мне просто нужно каким-то образом сделать это выражение выражением вызова, и оно будет работать, но я не уверен, как это сделать.

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

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

Любая помощь по этому вопросу будет принята с благодарностью!

5
задан Anupheaus 2 August 2012 в 20:15
поделиться