it-swarm-pt.tech

Consulta Linq com soma anulável

from i in Db.Items
select new VotedItem
{
    ItemId = i.ItemId,
    Points = (from v in Db.Votes
              where b.ItemId == v.ItemId
              select v.Points).Sum()
}

Eu tenho essa consulta, no entanto, ele falhará se nenhum voto for encontrado com exceção:

The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type.

Eu suponho que sua soma retorna um int e não um int anulável, dando soma a int? como entrada só dá o mesmo erro, provavelmente causa soma apenas os trabalhos em ints.

Qualquer boa solução para isso?

67
AndreasN
from i in Db.Items
select new VotedItem
{
    ItemId = i.ItemId,
    Points = (from v in Db.Votes
              where b.ItemId == v.ItemId
              select v.Points ?? 0).Sum() 
}

EDIT - ok que tal isso ... (Fotografar novamente desde que eu não conheço o seu modelo ...):

from i in Db.Items
select new VotedItem
{
    ItemId = i.ItemId,
    Points = (from v in Db.Votes
              where b.ItemId == v.ItemId)
              .Sum(v => v.Points) 
}
22
Rashack

Você deseja usar a forma anulável de Soma, portanto, tente converter seu valor em anulável:

from i in Db.Items
select new VotedItem
{
    ItemId = i.ItemId,
    Points = (from v in Db.Votes
              where b.ItemId == v.ItemId
              select v.Points).Sum(r => (decimal?) r.Points)
}

Seu problema é discutido aqui com mais detalhes: 

http://weblogs.asp.net/zeeshanhirani/archive/2008/07/15/applying-aggregates-to-empty-collections-causes-exception-in-linq-to-sql.aspx

73
Scott Stafford

Assumindo que "v.Points" é um decimal, use o seguinte:

from i in Db.Items
select new VotedItem
{
    ItemId = i.ItemId,
    Points = (from v in Db.Votes
              where b.ItemId == v.ItemId
              select (decimal?) v.Points).Sum() ?? 0
}
19
Jeroen Bernsen

Se você não gosta de converter para nullabe decimal, você também pode tentar usar o método Linq To Objects with ToList (),

LinqToObjects A soma da coleção vazia é 0, onde LinqToSql A soma da coleção vazia é nula.

11
Emir

Tente verificar isso:

var count = db.Cart.Where(c => c.UserName == "Name").Sum(c => (int?)c.Count) ?? 0;

Então, a raiz do problema é que a consulta SQL assim:

SELECT SUM([Votes].[Value])
FROM [dbo].[Votes] AS [Votes]
WHERE 1 = [Votes].[UserId] 

retorna NULL

10
Pavel Shkleinik

Uma solução simples, mas eficaz, seria somar os votos onde Points.Count> 0, para que você nunca tenha valores nulos:

from i in Db.Items
select new VotedItem
{    
  ItemId = i.ItemId,
  Points = (from v in Db.Votes
            where b.ItemId == v.ItemId &&
            v.Points.Count > 0
            select v.Points).Sum()
}
5
Razzie

Apenas para adicionar outro método na mistura :)

Where(q=> q.ItemId == b.ItemId && b.Points.HasValue).Sum(q=>q.Points.Value)

Eu tive um cenário semelhante, mas não estava comparando um campo adicional ao somar ...

Where(q => q.FinalValue.HasValue).Sum(q=>q.FinalValue.Value);
4
Phil

Assumindo que os pontos são uma lista de Int32, que tal algo como:

var sum = Points.DefaultIfEmpty().Sum(c => (Int32)c ?? 0)
3
ProfNimrod

Eu acho que este é o mesmo caso . Eu resolvi isso. Esta é minha solução:

var x = (from a in this.db.Pohybs
                 let sum = (from p in a.Pohybs
                            where p.PohybTyp.Vydej == true
                            select p.PocetJednotek).Sum()
                 where a.IDDil == IDDil && a.PohybTyp.Vydej == false
                 && ( ((int?)sum??0) < a.PocetJednotek)
                 select a);

Eu espero que isso ajude.

2
Pepa

Eu tive o mesmo problema. Resolvido com união de lista vazia:

List<int> emptyPoints = new List<int>() { 0 };

from i in Db.Items
select new VotedItem
{
 ItemId = i.ItemId,
 Points = (from v in Db.Votes
           where b.ItemId == v.ItemId
           select v.Points).Union(emptyPoints).Sum()
}

No caso de "Pontos" é inteiro isso deve funcionar.

2
Alex

Pode ser para colocar esta consulta em try/catch..if "exception", então não foram encontrados votos

1
0x49D1

Semelhante às respostas anteriores, mas você também pode converter o resultado da soma inteira para o tipo anulável.

from i in Db.Items
select new VotedItem
{
    ItemId = i.ItemId,
    Points = (decimal?)((from v in Db.Votes
              where b.ItemId == v.ItemId
              select v.Points).Sum()) ?? 0
}

Indiscutivelmente, isso é melhor para o que realmente está acontecendo, mas tem o mesmo efeito que o elenco em esta resposta .

0
OlduwanSteve
        (from i in Db.Items
         where (from v in Db.Votes
                where i.ItemId == v.ItemId
                select v.Points).Count() > 0
         select new VotedItem
         {
             ItemId = i.ItemId,
             Points = (from v in Db.Items
                       where i.ItemId == v.ItemId
                       select v.Points).Sum()
         }).Union(from i in Db.Items
                  where (from v in Db.Votes
                         where i.ItemId == v.ItemId
                         select v.Points).Count() == 0
                  select new VotedItem
                  {
                      ItemId = i.ItemId,
                      Points = 0
                  }).OrderBy(i => i.Points);

Isso funciona, mas não é muito bonito nem legível.

0
AndreasN

Pensei que eu iria jogar outra solução lá fora. Eu tive um problema semelhante e foi assim que acabei resolvendo:

Where(a => a.ItemId == b.ItemId && !b.IsPointsNull()).Sum(b => b.Points)
0
Jeff

Eu tive um problema semelhante e veio com a solução de obter o que eu estava tentando sair do banco de dados, fazer uma contagem sobre aqueles e, em seguida, apenas se eu tivesse algo retornado fazer uma soma. Não foi possível fazer o elenco trabalhar por algum motivo, então postar isso se alguém tiver problemas semelhantes.

por exemplo.

Votes = (from v in Db.Votes
          where b.ItemId = v.ItemId
          select v)

E, em seguida, verifique se você obteve algum resultado para que você não retorne null.

If (Votes.Count > 0) Then
    Points = Votes.Sum(Function(v) v.Points)
End If
0
tcmorris