Я действительно застрял на этом.У меня обширный опыт работы с SQL, но я только начал новую работу, и они предпочитают использовать LINQ для простых запросов.Поэтому в духе обучения я попытался переписать этот простой SQL-запрос:
SELECT
AVG([Weight] / [Count]) AS [Average],
COUNT(*) AS [Count]
FROM [dbo].[Average Weight]
WHERE
[ID] = 187
Для ясности, вот схема таблицы:
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])
)
Вот что япридумали:
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 - это объект Linq To SQL, созданный SQLMetal.Если я пытаюсь averageWeight.First()
, я получаю исключение OverflowException.Я использовал SQL Profiler, чтобы посмотреть, как выглядит параметризованный запрос, сгенерированный LINQ.Повторно с отступом, который выглядит так:
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
Излишнее вложение, я вижу только одну проблему: DECIMAL (29, 4).(Запрос выполняется и дает ожидаемый результат.) Насколько я понимаю, все, что выше 28, переполнит десятичный тип данных C #.[Count] - INT, поэтому его нужно конвертировать, но [Weight] - ДЕСЯТИЧНО (8, 4).Я понятия не имею, почему LINQ использовал бы такой большой тип данных.
Зачем LINQ CONVERT к типу данных, который вызывает и переполняется?Есть ли способ изменить это поведение?Или я даже на правильном пути?
Кроме того, Data.Context.AverageWeight был сгенерирован SqlMetal, и я проверил, что Вес является десятичным, а Атрибут столбца правильный (Десятичное число (8,4)).
Заранее спасибо.
Обновление: Таким образом, похоже, что LINQ to SQL может быть виновником.Я изменил свой LINQ следующим образом:
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() });
Теперь сгенерированный SQL выглядит следующим образом:
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]
В результате получается:
Average Count
0.000518750000000 16
Предыдущийподход дал:
Average Count
0.000518750000000000000 16
Переполнения больше нет, но запрос менее эффективен.Я не знаю, почему LINQ to SQL конвертируется в такую высокую точность.Не из других переменных так точны.И, насколько я могу судить, я ничего не могу сделать в LINQ, чтобы форсировать тип данных.
Есть идеи?