Подтвердить что ты не робот

Создание предиката многократного использования для EntitySet <T>, IQueryable <T> и IEnumerable <T>

В моей установке LINQ to SQL у меня есть разные таблицы, которые сопоставляются классам, которые в основном поддерживают один и тот же интерфейс для поддержки версий, т.е.

public interface IValid
{
    int? validTo { get; }
    int validFrom { get; }
}

Классы LINQ to SQL получают этот интерфейс следующим образом:

public partial class representationRevision : IValid
{
}

Теперь я хотел бы определить способ фильтрации DRY (Do not Repeat Yourself) EntitySet<T>, IEnumerable<T> и IQueryable<T>, чтобы результирующие списки были действительны для конкретной ревизии. Я пробовал сделать это:

public static class ExtensionMethods
{

    public static IQueryable<T> ValidFor<T>(this IQueryable<T> v, int? revision)
        where T : IValid
    {
        return v.Where(cr => ((cr.validFrom <= revision) &&
            ((cr.validTo == null) || (cr.validTo > revision)))
            || ((revision == null) && (cr.validTo == null))
            );
    }
}

Но это дает проблемы на EntitySet<T>. Я добавил специальную реализацию EntitySet, которая сначала вызывает AsQueryable(), но это создает исключение. Undeterred Я попытался сделать предикат, чтобы использовать метод Where(predicate):

    public static Expression<Func<contentRevision, bool>> IsValidFor(int? revision)
    {
        return ((cr) => ((cr.validFrom <= revision) &&
            ((cr.validTo == null) || (cr.validTo > revision)))
            || ((revision == null) && (cr.validTo == null)));
    }

При использовании с .Where<contentRevision>(IsValidFor(revision)) он дает такие ошибки, как:

Ошибка 5 'System.Data.Linq.EntitySet' делает     не содержит определения для "Где" и лучший метод перегрузки метода расширения     "System.Linq.Enumerable.Where(System.Collections.Generic.IEnumerable, System.Func) 'имеет     некоторые недопустимые аргументы

Обратите внимание, что это даже без использования интерфейса IValid... Я пытался использовать различные варианты этой темы (например, добавление параметра int), но все они, похоже, терпят неудачу. Любые указатели, которые помогут мне в правильном направлении?

4b9b3361

Ответ 1

Не уверен в EntitySet<T>, поэтому сосредоточимся на IQueryable<T> и IEnumerable<T>.

Чтобы поставщик LINQ оценивал деревья выражений, которые IQueryable<T> использует для своих аргументов выражения, необходимо обеспечить, чтобы базовый интерфейс сохранялся. В противном случае сделайте все в рамках IEnumerable<T> (т.е. Если вы в порядке, чтобы вытащить весь набор данных в локальную память, а затем обработайте его там, а не в базе данных, просто используйте LINQ для объектов).

Другой вариант - это метод расширения AsQueryable (часть класса Queryable), который преобразует IEnumerable<T> в IQueryable<T>, а затем вы можете поделиться остальной частью кода.

IQueryable<T> SomeSharedQuery(this IQueryable<T> source) {
    return source.(LINQ query operators...);
}
IQueryable<T> SomeSharedQuery(this IEnumerable<T> source) {
    return source.AsQueryable().SomeSharedQuery();
}

Итак, у вас есть общий код с адаптером.