2015-09-09 4 views
0

У меня есть код, написанный разработчиком. Я думаю, что его ужасно и не должно быть необходимымТерминальный код Linq Лучшее решение

value = s.Businesses.SelectMany(
    x => x.Payments.Where(
     w => w.total != 0 && 
     !w.jobId.HasValue && 
     w.createdAt >= Utility.monthS 
     && w.createdAt <= Utility.monthE) 
    ).Any() ? 
     s.Businesses.SelectMany(
      x => x.Payments.Where(
       w => w.total != 0 && 
       !w.jobId.HasValue && 
       w.createdAt >= Utility.monthS 
       && w.createdAt <= Utility.monthE) 
      ).Sum(su => su.quantity) 
     : 0; 

Причина это делает .Any до Sum является то, что записи без каких-либо значений в конечном итоге получить нулевые значения и может привести к ошибкам.

Есть ли лучший способ передовой практики написания.

+0

'Enumerable.Sum' когда вызывается в пустой коллекции, будет возвращаться 0. – juharr

+0

Я бы порекомендовал, по крайней мере, присвоить переменную 'SelectMany' переменной, поэтому вам нужно будет ее переходить только один раз. Затем используйте .Any и .Sum для переменной. Это приведет к более чистым взглядам. – Bob

ответ

7

Если это не было для Entity Framework, то Sum просто возвращать 0 для пустых коллекций и вам не нужно будет сделать Any

value = s.Businesses.SelectMany(
    x => x.Payments.Where(
     w => w.total != 0 && 
      !w.jobId.HasValue && 
      w.createdAt >= Utility.monthS && 
      w.createdAt <= Utility.monthE)) 
    .Sum(su => su.quantity); 

Однако, так как это для Entity Framework у вас есть вопрос он превращается в SQL и SUM в T-SQL вернет null для пустого набора. Таким образом, вы должны заменить эту последнюю строку с одним из следующих действий, чтобы заставить его работать

.Sum(su => (int?)su.quanity) ?? 0; 

или

.Select(su => su.quanity).DefaultIfEmpty().Sum(); 

Первый будет сказать C# ожидать возможного null и использовать 0, если это null , Второй заменит пустой результат набором с единственным значением по умолчанию, в этом случае 0.

Вы не хотите делать Any, а затем Sum, потому что это приведет к двум вызовам в БД.

+0

Это нормально работает, когда я запускаю его локально. И на самом деле возвращает 0. Однако при развертывании получает ошибку, как будто ее возвращающие нули. Именно поэтому разработчик реализовал это решение. См. Здесь для получения дополнительной информации об ошибке http://stackoverflow.com/questions/6864311/the-cast-to-value-type-int32-failed-because-the-materialized-value-is-null –

+0

@DaleFraser Ответ нужно было использовать «int?» и использовать '??' или 'DefaultIfEmpty (0) .Sum()', а не использовать 'Any'. – juharr

+0

Однако этот ответ @juharr неверен. «Но поскольку Sum просто вернет 0 для пустых коллекций, вам не нужно делать Any», но это не так. –

1

Вот как это будет выглядеть в синтаксисе запроса:

var payments = 
    from x in s.Businesses 
    from w in x.Payments 
    where 
    w.total != 0 && 
    !w.jobId.HasValue && 
    w.createdAt >= Utility.monthS && 
    w.createdAt <= Utility.monthE 
    select w; 

value = 
payments.Any() ? payments.Sum(p => p.Quantity) : 0; 

Как прокомментировали другие плакаты - Любой() не может быть даже необходимыми, поэтому последняя строка может быть value = payments.Sum(p => p.Quantity)

+0

Почему не просто 'value = (from ... select w.Quantity) .Sum();'? Также это называется синтаксисом запроса, а не чистым linq. – juharr

+0

Спасибо, @juharr. Я этого не знал, всегда называл это чистым :). Изменен мой ответ. – Alexander

Смежные вопросы