Can anyone tell me what is going on in this function??
In the following code snippet, user.Id = 0
, id.Value = 0
and id.SqlDbType = Int
.. as expected since user.Id
is an int field.
However, error.Value = null
and error.SqlDbType = BigInt
. What gives? If I use non-zero it detects an int and the correct value.
Note: the Value properties are the same before and after declaring the parameter direction.
public static long InsertUpdate(User user) {
SqlParameter id = new SqlParameter("@id", user.Id);
id.Direction = ParameterDirection.InputOutput;
cmd.Parameters.Add(id);
SqlParameter error = new SqlParameter("@error_code", 0);
error.Direction = ParameterDirection.Output;
cmd.Parameters.Add(error);
.... other stuff
}
As well, if @SET @error_Code = 0 in the sproc, error.Value = NULL and error.SqlDbType = NVarChar AFTER the procedure runs. If I set it to an integer I get an Int type.
UPDATE: After specifying SqlDbType.Int the parameter now has the correct SqlDbType before and after the command... however the stored procedure is still setting @error_code = null when I in fact set it to 0.
UPDATE: When the sproc executes the SELECT statement the @error_code parameter is always returned as null, regardless of when or not it has been set... this only happens when there's a select statement...
Here is the procedure to reproduce:
ALTER PROCEDURE [dbo].[usp_user_insert_v1]
@username VARCHAR(255),
@password VARCHAR(255),
@gender CHAR(1),
@birthday DATETIME,
@error_code INT OUTPUT
AS
BEGIN
-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;
DECLARE @default_dt DATETIME
EXEC @default_dt = uf_get_default_date
DECLARE @dt DATETIME = GETUTCDATE()
INSERT INTO users(username, password, gender, birthday, create_dt, last_login_dt, update_dt, deleted)
VALUES(@username, @password, @gender, @birthday, @dt, @default_dt, @default_dt, 0)
SELECT * FROM users WHERE id = SCOPE_IDENTITY()
SET @error_code = 3
RETURN
END
SOLUTION?
Found this link on the ASP forums... apparently you can't read the output parameter until you have read all the results from the SqlDataReader... very unfortunate for me since I decide whether or not I even WANT to read the results based on the output param...
Both of the current answers are slightly incorrect because they're based on the assumption that the constructor being called for your error
object is the (string,object)
one. This is not the case. A literal 0
can be converted to any enum type1, and such a conversion would be preferred over a conversion to object
. So the constructor being called is the (string,SqlDbType)
constructor.
So the type is set to BigInt
because that's the 0
value for the SqlDbType
enumeration, and the Value
is null because you have no code that attempts to set the value.
SqlParameter error = new SqlParameter("@error_code", (object)0);
should cause it to select the correct overload.
Demo:
using System;
using System.Data;
namespace ConsoleApplication
{
internal class Program
{
private static void Main()
{
var a = new ABC("ignore", 0);
var b = new ABC("ignore", (object)0);
var c = new ABC("ignore", 1);
int i = 0;
var d = new ABC("ignore", i);
Console.ReadLine();
}
}
public class ABC
{
public ABC(string ignore, object value)
{
Console.WriteLine("Object");
}
public ABC(string ignore, SqlDbType value)
{
Console.WriteLine("SqlDbType");
}
}
}
Prints:
SqlDbType
Object
Object
Object
1From the C# Language specification, version 5, section 1.10 (that is, just in the introduction to the language, not buried deep down in the language lawyery bits):
In order for the default value of an enum type to be easily available, the literal 0 implicitly converts to any enum type. Thus, the following is permitted.
Color c = 0;
I'd have also thought this important enough to be in the Language Reference on MSDN but haven't found a definitive source yet.