Обработка нулевых результатов с помощью метода LINQ Average()

Я новичок в LINQ и пытаюсь создать некоторые точки данных из таблицы в граф. Три поля важности в этой таблице - это идентификатор, время и значение. Я пишу запрос, чтобы получить среднее значение за определенное время для выбранного идентификатора. LINQ, который я написал, следует:

var value = (from t in _table
             where t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime
             select t.Value).Average();

Однако это приводит к сбоям во время выполнения:

"Нулевое значение не может быть присвоено член с типом System.Decimal который является типом значения, отличным от нуля."

В определенные промежутки времени нет данных, поэтому SQL LINQ генерирует null, что я хотел бы быть COALESCED равным 0, но вместо этого сбой приложения. Есть ли способ написать этот запрос LINQ, чтобы иметь возможность справиться с этим должным образом?

Определение таблицы, чтобы сделать все более ясным:

[Serializable]
[Table(Name = "ExampleTable")]
public class ExampleTable
{
    [Column(Name = "Id")]
    public int Id { get; set; }

    [Column(Name = "Time")]
    public DateTime Time { get; set; }

    [Column(Name = "Value")]
    public int Value{ get; set; }
}

Ответ 1

Я думаю, что вы хотите

var value = (from t in _table
             where t.Id == id
                && t.Time >= intervalStartTime
                && t.Time <= intervalEndTime
             select (int?)t.Value).Average()

Таким образом, вы получаете double? назад, тогда как без приведения (int?) вам нужно вернуть обратно double, который не может быть null.

Это из-за подписей

double Enumerable.Average(IEnumerable<int> source)
double? Enumerable.Average(IEnumerable<int?> source)

Теперь, чтобы получить среднее значение 0 вместо нуля, вам нужно поместить коалесцирующий оператор в конец

var value = (from t in _table
             where t.Id == id
                && t.Time >= intervalStartTime
                && t.Time <= intervalEndTime
             select (int?)t.Value).Average() ?? 0.0;

IMHO это довольно ужасный дизайн класса Enumerable/Queryable; почему не может Average(IEnumerable<int>) возвращать double?, почему только для Average(IEnumerable<int?>)?

Ответ 2

EDIT: Полное изменение:)

Хорошо, как насчет этого:

var value = (from t in _table
             where t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime
             select t.Value).DefaultIfEmpty().Average()

Я считаю, что логически то, что вы хотите - меняя {} на {0}, чтобы сделать все средние достижимыми. Я не знаю, будет ли он делать то, что вы хотите с точки зрения SQL.

Ответ 3

EDIT: Total Rework

Попробуйте сначала выставить значение с нулевым значением

var value = (from t in _table
         where t.Id == id
             && t.Time >= intervalStartTime
             && t.Time <= intervalEndTime
         select ((int?)t.Value) ?? 0).Average()

Ответ 4

Попробуйте следующее. Он просто пропустит все нулевые элементы, возвращаемые запросом.

var value = (from t in _table
             where t != null
             where t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime
             select t.Value).Average();

Если вы хотите явно обрабатывать нулевые элементы как ноль, то простое использование условного оператора должно выполнить задание:

var value = (from t in _table
             where t == null ||
                 (t.Id == id
                 && t.Time >= intervalStartTime
                 && t.Time <= intervalEndTime)
             select t == null ? 0 : t.Value).Average();

Ответ 5

Не могли бы вы использовать temp для начального запроса?

например:

var temp = (from t in _table
            where t.Id == id
                && t.Time >= intervalStartTime
                && t.Time <= intervalEndTime
            select t.Value) ??  new List<int>() {0};
var value = temp.Average();

Не уверен, что это помогает.