Как назначить значение свойства IQueryable ?

Я использую Entity Framework 4.1 Code First. В моей сущности у меня есть три свойства даты и времени:

public class MyEntity
{
    [Key]
    public Id { get; set; }

    public DateTime FromDate { get; set; }

    public DateTime ToDate { get; set; }

    [NotMapped]
    public DateTime? QueryDate { get; set; }

    // and some other fields, of course
}

В базе данных всегда указываются даты «От» и «До». Я запрашиваю их, используя простое предложение where. Но в результирующий набор я хочу включить дату, которую я запрашивал. Мне нужно сохранить это, чтобы работала другая бизнес-логика.

Я работаю над методом расширения, чтобы сделать это, но у меня возникают проблемы:

public static IQueryable<T> WhereDateInRange<T>(this IQueryable<T> queryable, DateTime queryDate) where T : MyEntity
{
    // this part works fine
    var newQueryable = queryable.Where(e => e.FromDate <= queryDate &&
                                            e.ToDate >= queryDate);

    // in theory, this is what I want to do
    newQueryable = newQueryable.Select(e =>
                                           {
                                               e.QueryDate = queryDate;
                                               return e;
                                           });
    return newQueryable;
}

Это не работает. Он работает, если я использую IEnumerable, но я хочу сохранить его как IQueryable, чтобы все работало на стороне базы данных, и этот метод расширения все еще можно использовать в любой части другого запроса. Когда это IQueryable, я получаю следующую ошибку компиляции:

Лямбда-выражение с телом оператора не может быть преобразовано в дерево выражения

Если бы это был SQL, я бы сделал что-то вроде этого:

SELECT *, @QueryDate as QueryDate
FROM MyEntities
WHERE @QueryDate BETWEEN FromDate AND ToDate

Итак, вопрос в том, как я могу преобразовать дерево выражения, которое я уже нужно включить это дополнительное присвоение собственности? Я просмотрел IQueryable.Expression и IQueryable.Provider.CreateQuery - где-то там есть решение. Может быть, к существующему дереву выражений можно добавить выражение присваивания? Я недостаточно знаком с методами дерева выражений, чтобы понять это. Есть идеи?

Пример использования

Чтобы уточнить, цель состоит в том, чтобы иметь возможность выполнить что-то вроде этого:

var entity = dataContext.Set<MyEntity>()
                        .WhereDateInRange(DateTime.Now)
                        .FirstOrDefault();

И сохранить DateTime.Now в QueryDate результирующей строки, БЕЗ наличия более одной строки возвращается из запроса к базе данных. (В решении IEnumerable несколько строк возвращаются до того, как FirstOrDefault выберет нужную строку.)

Другая идея

Я мог бы пойти дальше и сопоставить QueryDate как реальное поле и установить для его DatabaseGeneratedOption значение Computed. Но тогда мне понадобится какой-то способ внедрить «@QueryDate как QueryDate» в SQL, созданный операторами select EF. Поскольку он вычисляется, EF не будет пытаться предоставить значения во время обновления или вставки. Итак, как я могу внедрить пользовательский SQL в операторы select?

5
задан Matt Johnson-Pint 15 April 2011 в 18:15
поделиться