consulta LINQ con suma anulable
-
22-08-2019 - |
Pregunta
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()
}
Tengo esta consulta, sin embargo, falla si no hay votos se encontraron con una excepción:
The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type.
Asumo que es porque suma devuelve un int y no un int anulable, dando una suma int? como entrada sólo dan el mismo error, probablemente causar suma única workes en enteros.
Cualquier buena solución para esto?
Solución
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()
}
EDITAR - bien qué pasa con esto ... (toma de nuevo ya que no sé su 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)
}
Otros consejos
Usted desea utilizar la forma anulable de Suma, así que trata de la emisión de su valor a un anulable:
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)
}
Su tema se discute aquí en más detalle:
"Suponiendo v.Points" es un decimal sólo tiene que utilizar el siguiente:
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
}
Si no te gusta la fundición hasta nullabe decimal también se podría tratar de usar LINQ to Objects con el método ToList (),
LinqToObjects Suma de colección vacía es 0, donde LinqToSql Suma de colección vacía es nulo.
Trate de comprobar esto:
var count = db.Cart.Where(c => c.UserName == "Name").Sum(c => (int?)c.Count) ?? 0;
Por lo tanto, la raíz del problema es que la consulta SQL como esto:
SELECT SUM([Votes].[Value])
FROM [dbo].[Votes] AS [Votes]
WHERE 1 = [Votes].[UserId]
devuelve NULL
Una solución sencilla pero eficaz sería la única suma los votos donde Points.Count> 0, para que nunca tenga 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()
}
Sólo para añadir otro método en la mezcla:)
Where(q=> q.ItemId == b.ItemId && b.Points.HasValue).Sum(q=>q.Points.Value)
Yo tenía un escenario similar pero no estaba comparando un campo adicional al resumir ...
Where(q => q.FinalValue.HasValue).Sum(q=>q.FinalValue.Value);
Si se asume Puntos es una lista de Int32, ¿qué tal algo como:
var sum = Points.DefaultIfEmpty().Sum(c => (Int32)c ?? 0)
Yo tenía el mismo problema. Resuelto con la unión lista vacía:
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()
}
En el caso de "puntos" es número entero esto debería funcionar.
Creo que este es el mismo caso. Lo resolví. Esta es mi solución:
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);
Espero que esta ayuda.
(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);
Esto funciona, pero no es muy bonita o legible.
Yo tenía un problema similar y se acercó con la solución de conseguir lo que yo estaba tratando de salir de la base de datos, hacer un recuento de los y sólo si tenía algo regresado hacer una suma. No fue capaz de conseguir el modelo de trabajo por alguna razón lo que la publicación de este si alguien más tenía problemas similares.
por ejemplo.
Votes = (from v in Db.Votes
where b.ItemId = v.ItemId
select v)
Y a continuación, comprobar para ver si tienes ningún resultado para que no se les devuelve null.
If (Votes.Count > 0) Then
Points = Votes.Sum(Function(v) v.Points)
End If
Al igual que en las respuestas anteriores, pero también se puede emitir el resultado de la suma total al tipo anulable.
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
}
Podría decirse que esto mejor se adapte a lo que realmente está pasando, pero tiene el mismo efecto que el reparto en esta respuesta .
Pensaba que iba a tirar otra solución por ahí. Tenía un problema similar y así es como terminé resolverlo:
Where(a => a.ItemId == b.ItemId && !b.IsPointsNull()).Sum(b => b.Points)