Как создать метод расширения 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();
}