Переполнение преобразования LINQ в SQL

Я действительно застрял на этом. У меня обширный опыт работы с 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] - это DECIMAL (8, 4). Я понятия не имею, почему LINQ использует такой большой тип данных.

Зачем LINQ CONVERT к типу данных, который вызывает переполнение? Есть ли способ изменить это поведение? Или я даже на правильном пути?

Кроме того, Data.Context.AverageWeight был сгенерирован SqlMetal, и я подтвердил, что Weight является десятичным, а атрибут столбца верен (Decimal (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 я ничего не могу сделать, чтобы принудительно указать тип данных.

Есть идеи?

11
задан Ben 28 February 2011 в 17:58
поделиться