Estoy realmente atrapado en este. Tengo una amplia experiencia en SQL, pero acabo de comenzar un nuevo trabajo y ellos prefieren usar LINQ para consultas simples. Así, en el espíritu de aprendizaje, he tratado de volver a escribir esta simple consulta SQL:LINQ to SQL Conversion Overflows
SELECT
AVG([Weight]/[Count]) AS [Average],
COUNT(*) AS [Count]
FROM [dbo].[Average Weight]
WHERE
[ID] = 187
En aras de la claridad, aquí está el esquema de tabla:
CREATE TABLE [dbo].[Average Weight]
(
[ID] INT NOT NULL,
[Weight] DECIMAL(8, 4) NOT NULL,
[Count] INT NOT NULL,
[Date] DATETIME NOT NULL,
PRIMARY KEY([ID], [Date])
)
Esto es lo que ocurrió con :
var averageWeight = Data.Context.AverageWeight
.Where(i => i.ID == 187)
.GroupBy(w => w.ID)
.Select(i => new { Average = i.Average(a => a.Weight/a.Count), Count = i.Count() });
Data.Context.AverageWeight es un objeto Linq to SQL generado por SQLMetal. Si trato de averageWeight.First()
obtengo una OverflowException. Utilicé el Analizador de SQL para ver a qué se parece la consulta parametrizada generada por LINQ. Re-sangría que tiene este aspecto:
EXEC sp_executesql N'
SELECT TOP(1)
[t2].[value] AS [Average],
[t2].[value2] AS [Count]
FROM (
SELECT
AVG([t1].[value]) AS [value],
COUNT(*) AS [value2]
FROM (
SELECT
[t0].[Weight]/(CONVERT(DECIMAL(29, 4), [t0].[Count])) AS
[value],
[t0].[ID]
FROM [dbo].[Average Weight] AS [t0]
) AS [t1]
WHERE
([t1].[ID] = @p0)
GROUP BY
[t1].[ID]
) AS [t2]',
N'@p0 int',
@p0 = 187
anidación excesiva a un lado, sólo veo un problema: DECIMAL (29, 4). (La consulta se ejecuta y arroja el resultado esperado). Tengo entendido que cualquier elemento superior a 28 desbordará el tipo de datos decimales C#. [Count] es un INT, por lo que necesita ser CONVERTIDO, pero [Weight] es un DECIMAL (8, 4). No tengo idea de por qué LINQ usaría un tipo de datos tan grande.
¿Por qué LINQ CONVERT a un tipo de datos que causa y desborda? ¿Hay alguna forma de cambiar este comportamiento? ¿O estoy en el camino correcto?
También, Data.Context.AverageWeight fue generado por SqlMetal y verifiqué que Weight es un decimal y que Column Attribute es correcto (Decimal (8,4)).
Gracias de antemano.
Actualización: Parece que LINQ to SQL es el culpable. He cambiado de LINQ como esto:
var averageWeight = Data.Context.AverageWeight
.Where(i => i.ID == 187)
.GroupBy(w => w.ID)
.Select(i => new { Average = i.Average(a => a.Weight)/(decimal)i.Average(a => a.Count), Count = i.Count() });
Ahora el SQL generado es similar al siguiente:
SELECT TOP(1)
[t2].[value] AS [Average],
[t2].[value2] AS [Count]
FROM (
SELECT
AVG([t1].[value]) AS [value],
COUNT(*) AS [value2]
FROM (
SELECT
[t0].[Weight]/(CONVERT(DECIMAL(16, 4), [t0].[Count])) AS [value],
[t0].[ID]
FROM [dbo].[Average Weight] AS [t0]
) AS [t1]
WHERE
([t1].[ID] = 187)
GROUP BY
[t1].[ID]
) AS [t2]
El resultado de esto es:
Average Count
0.000518750000000 16
El enfoque anterior dio:
Average Count
0.000518750000000000000 16
Ya no es un desbordamiento, pero la consulta es menos eficiente. No sé por qué LINQ to SQL CONVERTIRÁ en una precisión tan alta. No de las otras variables son tan precisas. Y hasta donde puedo decir, no hay nada que pueda hacer en LINQ para forzar el tipo de datos.
¿Alguna idea?
El 'CONVERTIR (DECIMAL (...))' se está aplicando a * Count *, no a 'Weight'. –
¿Es esto Linq para SQL o Entity Framework? –
¿Por qué GroupBy en el LINQ pero no en el SQL original? –