12

I'm taking data that is in a List of Record objects and putting their contents in to a database:

// Processes a Record and adds it to the database
public bool addRecord(SqlConnection db, List<Record> recordsToAdd)
{
    using (SqlCommand command = db.CreateCommand())
    {
        foreach (Record record in recordsToAdd)
        {
            // Set the query command text
            command.CommandText = @"INSERT INTO SMDGROUP_STPRODMASTER (PRODCODE, TOTFREE, TOTPHYS, ITEMTYPE, PRODESC) VALUES ('@PRODCODE', '@TOTFREE', '@TOTPHYS', '@ITEMTYPE', '@PRODESC')";

            SqlParameter param1 = new SqlParameter("@CURSTAT", record.curstat);
            SqlParameter param2 = new SqlParameter("@ITEMDESC", record.itemdesc);
            SqlParameter param3 = new SqlParameter("@PRODCODE", record.prodcode);
            SqlParameter param4 = new SqlParameter("@TOTFREE", record.totfree);
            SqlParameter param5 = new SqlParameter("@TOTPHYS", record.totphys);
            SqlParameter param6 = new SqlParameter("@ITEMTYPE", record.itemtype);
            SqlParameter param7 = new SqlParameter("@PRODESC", record.proddesc);

            command.Parameters.Add(param1);
            command.Parameters.Add(param2);
            command.Parameters.Add(param3);
            command.Parameters.Add(param4);
            command.Parameters.Add(param5);
            command.Parameters.Add(param6);
            command.Parameters.Add(param7);

            // Execute the query
            command.ExecuteNonQuery();
        }
        return true;
    }
}

Here's my Record class:

class Record
{
    public string curstat { get; set; }
    public string itemtype { get; set; }
    public string itemdesc { get; set; }
    public string prodcode { get; set; }
    public string proddesc { get; set; }
    public string totfree { get; set; }
    public string totphys { get; set; }
}

Just from looking at the code, I've got a feeling that there is a shorter way of achieving this.

But secondly, I'm not even sure if I've done it correctly that the @PARAMETER values are being replaced.

If I view the contents of command, it still shows the query string with the @ parameters.

Also, I'm getting this error on command.ExecuteNonQuery():

String or binary data would be truncated.

The statement has been terminated.

So, my questions are:

  • Is there a shorter way to set and add multiple parameters to the query?
  • What could be causing the error?
6
  • 1
    What is the definition of your Record type? Commented Nov 16, 2011 at 8:45
  • 2
    The error is probably caused by trying to insert data into a column that is not large enough to store it. For example trying to store abcdef in a varchar(5) would cause this error. Commented Nov 16, 2011 at 8:46
  • I've added the class to the question now, thank you! Commented Nov 16, 2011 at 8:51
  • Create an array of parameters, and add it using AddRange. Commented Nov 16, 2011 at 8:56
  • Thanks everyone! I've decided to go with Royi's approach Commented Nov 16, 2011 at 12:46

9 Answers 9

21

You have a bigger constructor:

 command.Parameters.Add(
    "@CategoryName", SqlDbType.VarChar, 80).Value = "toasters";
Sign up to request clarification or add additional context in comments.

2 Comments

The benefit of this approach is that will truncate the data to the specified data size and type
The downside to that approach is that is will silently corrupt your data without any warning. I don't agree with the approach that Microsoft took on this. It really should throw an exception, not silently truncate your data.
5

Using the method AddWithValue will make the code a little bit shorter:

command.Parameters.AddWithValue("@CURSTAT", record.curstat);
//...

1 Comment

You should check out Can we stop using AddWithValue() already? and stop using .AddWithValue() - it can lead to unexpected and surprising results...
3

I do it a bit differntly.

I have both a extension method and a static method to create SqlParameters.

public static SqlParameter ToParam(this object v,string name){
return new SqlParameter(name,v);
}

Then I do something like this:

var p = new List<SqlParameter>();
p.Add(record.curstat.ToParam("@curstat"));
p.Add(record.itemdesc.ToParam("@itemdesc"));
//etc...

command.Parameters.AddRange(p.ToList());

Comments

2

The String or binary data would be truncated. most likely means your putting too many characters into one of your VARCHAR fields. I.e., if your column PRODDESC is a VARCHAR(50), and the string you're trying to insert is 70 characters, you will see that error.

Others have addressed alternative ways of doing the parameters so you can reduce the lines of code.

Comments

2

For a shorter syntax, you can use AddRange method of the SqlParameterCollection class. It means:

command.Parameters.AddRange(new [] {
    new SqlParameter(...),
    new SqlParameter(...),
    new SqlParameter(...) });

The error you're getting indicates that a string value doesn't fit in the table column or parameter, and is being truncated. You should check the length of the column in comparison to the data being inserted, or specify the length of parameters using another overload of the SqlParameter constructor.

Comments

1

If you wanted to use the following class:

Class MyParam
{
    public string name {get;set;}
    public object value {get;set;}
}

then you could have a List called myParams and do:

foreach(var p in myParams) command.Parameters.AddWithValue(p.name, p.value);

You obviously have to link the parameters and values somehow and there's no way around that. But if you do it in a class like this then the code that actually does the action is only one line long.

Comments

1

I think the message

String or binary data would be truncated.

The statement has been terminated.

comes from an error in your Command Text: in the SQL Query the parameters, even if they are strings, do not need to be quoted.

Replace the command with this

command.CommandText = @"INSERT INTO SMDGROUP_STPRODMASTER 
      (PRODCODE, TOTFREE, TOTPHYS, ITEMTYPE, PRODESC) 
      VALUES (@PRODCODE, @TOTFREE, @TOTPHYS, @ITEMTYPE, @PRODESC)";

To shorten the code i think you could add somewhere (for example in your record class or in an helper class) a method that creates an array of parameter from a record object and then call the AddRange function. It should keeps this function cleaner and you could use it also in other part of you code.

Comments

1

In regards to the error, it's a truncation problem i.e. the length of your parameter is longer than what your column can hold. To resolve this, be more specific when passing your parameters e.g. new SqlParameter("@MyParameter", SqlDbType.VarChar, 30).

Personally I don't think their is anything wrong with how your currently adding the parameters it's readable and does the job. If, however, you want to reduce the amont of lines of code in your function you could either go with what @Royi has suggested or simply package up the parameter adding into another method.

5 Comments

Actually Tim's answer is more correct. That exception isn't about the parameter size, but about the column size.
@BrandonMoore - If you read my answer I clearly state your column is expecting less characters than what your parameter is giving i.e. the parameter data is overflowing the column size. It's the same answer worded differently - I have updated to be even more clear.
Fair enough. I was focused on the part about "To get around this you should be more specific when passing your parameters".
Yeah just re-read that part and it appears as though I am suggesting a "workaround" instead of the correct approach. Updated.
It wasn't unclear. I was just mistaken for believing passing too large a value to a parameter would still cause an error.
0

This worked for me:

     comando.Parameters.Add(
            "@EmailAddress", SqlDbType.VarChar).Value = EmailAddress;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.