4

This error has me very confused. I have a stored procedure with two output parameters as defined below

@agentNumber int OUTPUT,
@currentAgentNum int OUTPUT,

They are then populated using the SELECT statements below

SELECT @agentNumber = AgentNumber
FROM AgentIdentification
WHERE AgentTaxId = @ssn

SELECT @currentAgentNum = AgentNumber
FROM UniqueAgentIdToAgentId
WHERE AgentId = @agentId

In the database, AgentNumber is defined in both tables, as an int. However, when I call this stored procedure in my C# code, I get a SQL exception stating:

Error converting data type int to nvarchar.

If I change the data types of the output parameters to nvarchar, the code will execute, however it will only return nothing more than the first digit of the whole number. Below is how the variables are defined in the C# code

SqlParameter outNewAgentNumber = new SqlParameter("@agentNumber", "");//Output parameter - leave blank
SqlParameter outCurrentAgentNumber = new SqlParameter("@currentAgentNum", "");//Output parameter - leave blank

outNewAgentNumber.Direction = ParameterDirection.Output;
outCurrentAgentNumber.Direction = ParameterDirection.Output;

I add these parameters to a SqlCommand object, specify the appropriate database and commandType, then use .ExecuteNonQuery() to call the procedure. Again, what has me really confused is the error message stating that I'm using nvarchar as a data type, which could only (to the best of my knowledge) be referring to something on the database side. However, as I said I've double/triple checked and both AgentNumber columns are of type int.

EDIT

Changing the sqlParameter declarations to a starting value of 0 has solved this issue. I'm now running into the same problem with two other parameters.

SqlParameter outOperator = new SqlParameter("@operator", "");//Output parameter - leave blank
SqlParameter outDate = new SqlParameter("@date", "");//Output parameter - leave blank
NealR
  • 10,189
  • 61
  • 159
  • 299

2 Answers2

4

Change

SqlParameter outNewAgentNumber = new SqlParameter("@agentNumber", "");//Output parameter - leave blank 
SqlParameter outCurrentAgentNumber = new SqlParameter("@currentAgentNum", "");//Output parameter - leave blank 

to

SqlParameter outNewAgentNumber = new SqlParameter("@agentNumber", 0);//Output parameter - leave blank 
SqlParameter outCurrentAgentNumber = new SqlParameter("@currentAgentNum", 0);//Output parameter - leave blank 

In your code, you're initially specifying the value as a string because you are passing it a string, which maps to a varchar when going from the CLR type to the SQL Data Type.

Once the runtime sees it as a string, it retains the same type throughout code, so if you assign a numeric (int) value, it still sees it as a string. The trick is to assign it the correct data type in the first place.

Community
  • 1
  • 1
David
  • 72,686
  • 18
  • 132
  • 173
3

These two lines are the culprits:

SqlParameter outNewAgentNumber = new SqlParameter("@agentNumber", "");
SqlParameter outCurrentAgentNumber = new SqlParameter("@currentAgentNum", "");

By specifying an empty string ("") as the second parameter, the ADO.NET runtime assumes it's a string paramter. And since you didn't specify any lengths - it probably defaults to just one character length (that's why it's returning only the first digit).

So, my recommendation would be to always explicitly define the datatype (and if it's a string - also define a length!) for your SQL parameters:

SqlParameter outNewAgentNumber = new SqlParameter("@agentNumber", SqlDbType.Int);
outNewAgentNumber.Direction = ParameterDirection.Output;
outNewAgentNumber.Value = 0;

or

SqlParameter outNewAgentNumber = new SqlParameter("@agentNumber", SqlDbType.NVarChar, 50);
outNewAgentNumber.Direction = ParameterDirection.Output;
outNewAgentNumber.Value = "";
marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Why do you recommend explicitly defining the length of the parameter? The cost of letting .net and SQL server derive it for you is extremely small and if you get it wrong (or it changes) the data will be truncated silently. Is that really the best approach? – Conrad Frix Aug 20 '12 at 17:18
  • @ConradFrix: the trouble can be, that if you don't specify the length, it could be set to 1 - usually *not* what you want .... – marc_s Aug 20 '12 at 17:25
  • @marc_s Are you suggesting that the parameter size get's derived from the parameter.value. Because that's not what happens.Also why are you setting the value when the direction isn't in (ParameterDirection.InputOutput, ParameterDirection.Input) – Conrad Frix Aug 20 '12 at 17:36
  • @ConradFrix: well - if the direction is **NOT** the default (`.Input`), you have to set it - no?? – marc_s Aug 20 '12 at 18:24
  • @marc_s sorry I should have written that differently. I meant to ask, why did you set the `Parameter.Value` when the direction of the parameter is output? – Conrad Frix Aug 20 '12 at 22:06
  • @ConradFrix: I think I recall cases where I ran into exceptions if the values - even of Output parameters - hadn't been initialized. So it's become a habit to just always initialize those values to something so I can also see whether a value has been returned from the proc - or whether I still have the initial values in there. – marc_s Aug 21 '12 at 04:57