Получение среднего значения вычисляемого элемента с помощью Nullable DateTime - PullRequest
2 голосов
/ 01 октября 2010

Ужасное название, я знаю ...

Это работает и дает мне то, что я ищу, но я знаю, что должен быть лучший способ сделать это:

var query = (from a in DB
             where a.Date.HasValue
             select a).AsEnumerable();

double avg = (from a in query
              select (a.Date.Value.Subtract(a.OtherDate).Days).Average();

По сути, a.Date - это обнуляемая дата-время, и я хочу получить среднее значение (a.Date - a.OtherDate) только тогда, когда a.Date существует (иначе расчет не будет работать).

Подобные вещи не будут работать:

double avg = (from a in DB
              where a.Date.HasValue
              select a.Date.Value.Subtract(a.OtherDate).Days).Average();

Я знаю, что видел подобные проблемы, когда решением было явным образом установить для поля Nullable значение NULL, которое заставило бы работать метод Average.Я не видел , где обнуляемое поле было частью вычислений, подобных этому.

Заранее спасибо.

Редактировать: Очиститьвсе немного, позвольте мне дать вам решение Бена и сообщение об ошибке, которое оно генерирует.Я должен признать, что я упустил еще одну часть ... a.OtherDate на самом деле немного сложнее ... позвольте мне проиллюстрировать:

var avg = DB.Where(a => a.Date.HasValue)
            .Where(a => a.ForeignKeyReference.Date.HasValue)
            .Select(a => a.Date.Value.Subtract(a.ForeignKeyReference.Date.Value).Days)
            .Average();

... и ошибку:

InvalidOperationException: Не удалось перевести выражение 'Таблица (БД). Где (a => a.Date.HasValue) .Where (a => a.ForeignKeyReference.Date.HasValue) .Select (a => a.Date.Value.Subtract (a.ForeignKeyReference.Date.Value) .Days) .Average () 'в SQL и не может обрабатывать его как локальное выражение.

Похоже, что метод "Subtract" или свойство "Days"не имеет перевода на SQL.Мой первый пример работал, потому что второй запрос был LINQ к объектам.Кто-нибудь знает, есть ли способ написать запрос LINQ таким образом, который будет переводить в SQL?

Ответы [ 3 ]

2 голосов
/ 01 октября 2010

Как насчет

double AvgDays = dates.Where(d => d.Date.HasValue)
                        .Average(dd => (dd.Date.Value-dd.OtherDate).Days);

, но, может быть, что-то вроде этого более полезно

var ticks = (long)dates.Where(d => d.Date.HasValue)
                        .Average(dd => (dd.Date.Value - dd.OtherDate).Ticks);

var avg = new TimeSpan(ticks);

Console.WriteLine("It's " + avg.Days + " days and " + avg.Hours + " hours and " + avg.Seconds + " seconds.");
0 голосов
/ 01 октября 2010

Вероятно, следовало бы прочитать сообщение об ошибке чуть ближе. Похоже, что для метода «Вычитание» просто нет перевода в SQL, но вы можете просто вычесть одну дату из другой, чтобы создать дату и время, например:

var query = from a in DB
            select (a.Date.Value - a.ForeignKeyReference.Date.Value);

Значение решения было:

var query = (from a in DB
             where a.Date.HasValue
             where a.ForeignKeyReference.Date.HasValue
             let ts = (TimeSpan)(a.Date.Value - a.ForeignKeyReference.Value)
             select ts.Days).Average();

Ответ Йонаса Эльфстрёма был верным, я просто добавляю это, так как это касается фактической причины проблемы.

0 голосов
/ 01 октября 2010

Что-то вроде этого определенно работает - я проверил правильность вывода, используя 3.5 sp1 framework:

var avg = DB
    .Where(a => a.Date.HasValue)
    .Select(a => a.Date.Value.Subtract(a.OtherDate).Days)
    .Average();

Оператор Where () гарантирует, что любые элементы с a.Date, имеющие нулевое значение, будут исключены из среднего значения; это поведение, которое вы указали, что вы хотели, правильно?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...