Обработка нулевых результатов с помощью метода 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();
Не уверен, что это помогает.