Как создать метод расширения Prepend для IQueryable<T>, который совместим с Linq для Entities 4.0?

Для проекта, использующего LINQ to Entities 4.0, у меня есть настройка, в которой мне нужно возвращать запрос с добавленным (постоянным) значением. Если бы я кодировал его в SQL, это выглядело бы примерно так:

select 0 as ID, 'default' as Name
union
select ID, Name from X

Для этого проекта я хотел бы создать общий метод расширения для IQueryable, который принимает постоянное значение, возвращает запрос с постоянным значением, добавленным в качестве его результата. Процесс не должен вызывать перечисление, так как я не хочу, чтобы запрос вызывал попадание в базу данных, если только другой код в приложении фактически не перечисляет запрос.

В идеале я хотел бы, чтобы результат IQueryable был присоединяемым к другим запросам Linq to Entities и обрабатывался поставщиком L2E.

Я попробовал пару изречений, но понял, что они будут вызывать перечисление вместо добавления к запросу. Моя последняя попытка расширить запрос без перечисления (по желанию), но возвращает ошибку:

    public static IQueryable<T> Prepend<T>(
        this IQueryable<T> query
        , T value
        )
    {
        return query
            .Where(t => false).DefaultIfEmpty(value)
            .Concat(query);
    }

Ошибка: "Невозможно создать постоянное значение типа" OCEAN.Business.Pocos.ExclusionIncomeType ". В этом контексте поддерживаются только примитивные типы (" например, Int32, String и Guid ")".

Я пытался найти похожие понятия, включая добавление значения, но безрезультатно.

Идеи?

3 ответа

Решение

Окончательный ответ:

    private static IEnumerable<T> PrependEnumerator<T>(this IEnumerable<T> sequence, T value)  
    { 
        yield return value; 
        foreach (var item in sequence) 
        { 
            yield return item; 
        } 
    } 

    public static IQueryable<T> Prepend<T>(
        this IQueryable<T> query
        , T value
        )
    {
        return query.PrependEnumerator(value).AsQueryable();
    }

Вы можете использовать итератор для создания нового IEnumerable<T> экземпляр, который сначала возвращает ваше значение по умолчанию:

public static IEnumerable<T> Prepend<T>(this IEnumerable<T> sequence, T value) 
{
    yield return value;
    foreach (var item in sequence)
    {
        yield return item;
    }
}

Это создаст перечислитель, который сначала вернет элемент по умолчанию, а затем перечислит запрос.

private static IEnumerable<T> PrependEnumerator<T>(
    this IEnumerable<T> sequence, 
    T value
    ) 
{ 
    yield return value; 
    foreach (var item in sequence) { yield return item; } 
} 
public static IQueryable<T> Prepend<T>( 
    this IQueryable<T> query , 
    T value 
    ) 
{ 
    return query.PrependEnumerator(value).AsQueryable(); 
} 
Другие вопросы по тегам