Какой тип данных в C# следует использовать для ввода данных в десятичный столбец в T-SQL?

Мне трудно понять, какой тип данных я бы использовал в С# для ввода данных в мою таблицу в моей базе данных, которая содержит десятичное число (5,2). Когда я попытался использовать десятичный тип данных С#, он сказал, что произошла ошибка при преобразовании числовых значений в десятичные. Когда я попробовал строку, она сказала, что не может преобразовать nvarchar в десятичную. Когда я попробовал float... Произошло то же самое, за исключением того, что оправданием был «настоящий» тип данных. двойной тоже не сработал.

У меня есть хранимая процедура, которая вводит данные в мою таблицу, но прежде чем я запускаю и привожу типы данных в моей хранимой процедуре к фактическому десятичному числу, есть ли другой способ, которым я могу преобразовать тип данных С#, чтобы он соответствовал моему десятичному числу ( 5,2) поле?

private void btnAddClientComputer_Click(object sender, EventArgs e)
{
    SQLCommands comm = new SQLCommands();
    try
    {
        comm.AddClientComputer(int.Parse(cbCustomerID.Text), cbAction.Text, decimal.Parse(tbCost.Text));
    }
    catch (FormatException)
    {
        MessageBox.Show("The cost you have entered is invalid. Please ensure the cost is above 0, and is an actual number", "Invalid Input at Cost", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
    }
}

...

public void AddClientComputer(int CustomerID, string Action, decimal Cost)
{
    try
    {
        comm = new SqlCommand("UspAddClientComputer", conn); // Stored Procedure - see sql file
        comm.Parameters.AddWithValue("@CustomerID", CustomerID);
        comm.Parameters.AddWithValue("@Action", Action);
        comm.Parameters.AddWithValue("@Cost", Cost);
        comm.CommandType = CommandType.StoredProcedure;
        comm.ExecuteNonQuery();
    }
    catch (Exception ex)
    {
        System.Windows.Forms.MessageBox.Show(ex.Message, "Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
    }
}

...

CREATE TABLE ClientComputers
            (ClientComputerID int Identity(1,1) primary key clustered
            ,CustomerID int
            ,Action varchar(7) check (Action = 'Upgrade' OR Action = 'Store')
            ,Cost decimal(5,2) check (Cost > 0)
            ,Constraint FKCustomerComputer FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID));
Go

...

CREATE PROCEDURE uspAddClientComputer @CustomerID int, @Action varchar(7), @Cost decimal(5,2)
AS
BEGIN TRY
    BEGIN TRANSACTION TrnAddClientComputer;
     INSERT INTO [TCTdb].[dbo].[ClientComputers]
           ([CustomerID]
           ,[Action]
           ,[Cost])
     VALUES
           (@CustomerID
           ,@Action
           ,@Cost)
    COMMIT TRANSACTION TrnAddClientComputer;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION TrnAddClientComputer;

    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    SELECT 
        @ErrorMessage = ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();

    RAISERROR (@ErrorMessage,
               @ErrorSeverity,
               @ErrorState
               );
END CATCH
GO

введите здесь описание изображения


person Eon    schedule 31.07.2011    source источник
comment
.NET decimal был бы логичным и наиболее подходящим выбором... можете ли вы показать нам какой-нибудь код, который вызвал эту ошибку, которая у вас была??   -  person marc_s    schedule 01.08.2011
comment
Конечно. Дайте мне время, чтобы отредактировать мой пост   -  person Eon    schedule 01.08.2011
comment
Используете ли вы десятичное число (5,2) для параметра хранимой процедуры?   -  person sll    schedule 01.08.2011
comment
ну, после редактирования моего поста я вижу да :D   -  person Eon    schedule 01.08.2011
comment
Просто интересно: у вас есть DECIMAL(5,2) - какой диапазон значений вы ожидаете, что этот тип сможет удерживать ?? Есть ли шанс, что вы можете ожидать 5 цифр до и 2 цифры после запятой? Это было бы неверно - dec(5,2) означает: 5 цифр всего, 2 из которых после запятой - так что вы ограничиваете себя значениями до макс. 999.99. Может ли это быть ядром проблемы в конце концов??   -  person marc_s    schedule 01.08.2011
comment
Ценная информация. спасибо, кажется, я был не на той стороне.   -  person Eon    schedule 01.08.2011


Ответы (3)


Проверять

 comm.Parameters.Add(new SqlParameter("@Cost", Cost));

КСТАТИ,

вы можете реорганизовать следующий блок

 try
    {
        comm.AddClientComputer(int.Parse(cbCustomerID.Text), cbAction.Text, decimal.Parse(tbCost.Text));
    }
    catch (FormatException)
    {
        MessageBox.Show("The cost you have entered is invalid. Please ensure the cost is above 0, and is an actual number", "Invalid Input at Cost", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
    }

to

// TODO: do the same for int.Parse as well
decimal userDefinedCost;
if (decimal.TryParse(tbCost.Text, out userDefinedCost))
{
     comm.AddClientComputer(int.Parse(cbCustomerID.Text), cbAction.Text, userDefinedCOst);
}
else
{
     MessageBox.Show("The cost you have entered is invalid. Please ensure the cost is above 0, and is an actual number", "Invalid Input at Cost", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
person sll    schedule 31.07.2011
comment
неудачно. этот код выше все еще дает мне ту же ошибку. Однако дал мне идею. Во-первых, я фейспалмил за использование десятичной дроби, мог бы использовать небольшие деньги. но теперь это может быть интересно узнать, как решить еще ... - person Eon; 01.08.2011
comment
@Eon Rusted du Plessis: что, если вы используете самый конкретный код: SqlParameter param = new SqlParameter("@cost", SqlDbType.Decimal, 5); param.Precision = 2; - это имеет значение? - person marc_s; 01.08.2011
comment
Я вижу, работает ли это, но, как указано в моем ответе, я изменил свой десятичный тип данных на smallmoney, так как работал со стоимостью услуги. Десятичный формат был удобен в использовании (если я заставил его работать), но моя интуиция подсказывает, что smallmoney может быть лучше (тип данных money больше, и почти никто не НАСТОЛЬКО богат) - person Eon; 01.08.2011

Я бы посоветовал вам добавить десятичный параметр с указанным типом. Это означает не просто использование AddWithValue, а создание объекта Parameter.

Я подозреваю, что проблема вызвана тем, что код не может быть преобразован чисто.

Расчетное время прибытия:

Ваш код был

comm.Parameters.Add("@Cost",SqlDbType.Decimal);
comm.Parameters["@Cost"].Value = Cost;

Вам нужно сделать что-то вроде (как я уже сказал, у меня нет легко доступной проверки синтаксиса)

SqlParameter param= new SqlParameter("@Cost", SqlDbType.Decimal, Cost);//there are more parameters which I cannot remember
comm.Parameters.Add(param);

Важно создать объект, в который вы можете передать все параметры, которые могут четко определить его как десятичное число SQL.

person Schroedingers Cat    schedule 31.07.2011
comment
Хорошо, я использовал объект параметра (я думаю). Я сказал comm.Parameters.Add(@Cost,SqlDbType.Decimal); затем следует comm.Parameters[@Cost].Value = Cost; Выдал мне ту же ошибку - person Eon; 01.08.2011
comment
Вы пробовали мою версию, используя новый SqlParameter(...)? У меня тот же код, использующий SP + decimal(,), и все работает нормально - person sll; 01.08.2011
comment
Просто иметь. Та же ошибка. Я попробую что-нибудь быстро. Возможно, это был неправильный тип данных, который мне пришлось использовать. - person Eon; 01.08.2011
comment
Хорошо, я решил свою проблему, но это далеко не то, что случилось с этим вопросом. Я опубликую свой ответ сейчас. - person Eon; 01.08.2011

Я нашел способ решить мою проблему в сложившихся обстоятельствах, благодаря тому, что обратил внимание на несколько вещей. Следующий код работал для меня.

private void btnAddClientComputer_Click(object sender, EventArgs e)
{
    SQLCommands comm = new SQLCommands();
    double trycost;
    if (double.TryParse(tbCost.Text,out trycost))
    {
        comm.AddClientComputer(int.Parse(cbCustomerID.Text), cbAction.Text, trycost);
    }
    else
    {
        MessageBox.Show("The cost you have entered is invalid. Please ensure the cost is above 0, and is an actual number", "Invalid Input at Cost", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
    }
}

...

public void AddClientComputer(int CustomerID, string Action, double Cost)
    {
        try
        {
            comm = new SqlCommand("UspAddClientComputer", conn); // Stored Procedure - see sql file
            comm.Parameters.AddWithValue("@CustomerID", CustomerID);
            comm.Parameters.AddWithValue("@Action", Action);
            comm.Parameters.Add(new SqlParameter("@Cost",Cost));
            comm.CommandType = CommandType.StoredProcedure;
            comm.ExecuteNonQuery();
        }
        catch (Exception ex)
        {
            System.Windows.Forms.MessageBox.Show(ex.Message, "Error", System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
        }
    }

.. А вот и часть решения. Я заменил Decimal(5,2) на smallmoney.

CREATE TABLE ClientComputers
            (ClientComputerID int Identity(1,1) primary key clustered
            ,CustomerID int
            ,Action varchar(7) check (Action = 'Upgrade' OR Action = 'Store')
            ,Cost smallmoney check (Cost > 0)
            ,Constraint FKCustomerComputer FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID));
Go

---------STORED PROCEDURES
--ADD CLIENT COMPUTER
CREATE PROCEDURE uspAddClientComputer @CustomerID int, @Action varchar(7), @Cost smallmoney
AS
BEGIN TRY
    BEGIN TRANSACTION TrnAddClientComputer;
     INSERT INTO [TCTdb].[dbo].[ClientComputers]
           ([CustomerID]
           ,[Action]
           ,[Cost])
     VALUES
           (@CustomerID
           ,@Action
           ,@Cost)
    COMMIT TRANSACTION TrnAddClientComputer;
END TRY
BEGIN CATCH
    ROLLBACK TRANSACTION TrnAddClientComputer;

    DECLARE @ErrorMessage NVARCHAR(4000);
    DECLARE @ErrorSeverity INT;
    DECLARE @ErrorState INT;

    SELECT 
        @ErrorMessage = ERROR_MESSAGE(),
        @ErrorSeverity = ERROR_SEVERITY(),
        @ErrorState = ERROR_STATE();

    RAISERROR (@ErrorMessage,
               @ErrorSeverity,
               @ErrorState
               );
END CATCH
GO

Спасибо всем, кто пытался. Это ответило на мой вопрос. Правильная идея, НЕПРАВИЛЬНЫЙ тип данных.

person Eon    schedule 31.07.2011
comment
Приятно слышать, что вы разобрались, но все еще не ясно, почему decimal(,) не работает для вас, взгляните на эту статью a2zmenu.com/Blogs/Sql/Arithmetic-overflow-error.aspx - person sll; 01.08.2011
comment
Возможно ли, что это ошибка? ваш код кажется правильным способом (сейчас здесь около 11 вечера, я устал и не могу сосредоточиться). Это может быть что-то гораздо более глубокое. что, если десятичная дробь (5,2) слишком мала? Я протестировал его со значением 4599,95 (Предполагается, что он будет работать с южноафриканским рэндом). - person Eon; 01.08.2011
comment
Да, вы можете, например, определить decimal(8,3) и попробовать - person sll; 01.08.2011
comment
Возможно, это было именно так. Я копался на складе. Спасибо за вашу помощь - person Eon; 01.08.2011