.NET SqlParameter构造函数不一致?

时间:2014-01-28 03:14:44

标签: sql .net stored-procedures sqlparameter

有谁能告诉我这个功能发生了什么? 在以下代码段中,user.Id = 0id.Value = 0id.SqlDbType = Int ..正如预期的那样user.Id是一个int字段。

但是,error.Value = nullerror.SqlDbType = BigInt。是什么赋予了?如果我使用非零,它会检测到int和正确的值。

注意:在声明参数方向之前和之后,Value属性是相同的。

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
}

同样,如果在sproc中@SET @error_Code = 0,则错误.Value = NULL并且错误.SqlDbType = NVarChar在程序运行之后。如果我将它设置为整数,我会得到一个Int类型。

更新: 在指定SqlDbType.Int之后,参数现在在命令之前和之后具有正确的SqlDbType ...但是当我实际上将其设置为0时,存储过程仍然设置@error_code = null。

更新: 当sproc执行SELECT语句时,@ error_code参数总是返回为null,无论它是否已经设置...只有当有一个select语句时才会发生...

以下是重现的过程:

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

解吗

http://forums.asp.net/t/1208409.aspx?Interesting+problem+with+getting+OUTPUT+parameters+from+SQL+Server+using+C+

在ASP论坛上找到这个链接......显然你不能读取输出参数,直到你读完SqlDataReader的所有结果...对我来说非常不幸,因为我决定是否我想读基于输出参数的结果......

3 个答案:

答案 0 :(得分:2)

来自SqlParameter.Value on MSDN

  

对于输出和返回值参数,该值在SqlCommand

完成时设置

即。我不会依赖类型推断来隐式设置返回类型。 我会明确设置输出参数的类型:

var error = new SqlParameter("@error_code", SqlDbType.Int)
{
    Direction = ParameterDirection.Output
};

修改

经过一些SqlParameter的反思:

BigInt很容易解释 - 它是默认的SqlDbTypeSqlParameter(string parameterName, object value) ctor不会覆盖此值。

public enum SqlDbType
{
  BigInt = 0,
  ...

Re:@error_code返回为NULL

我唯一能想到的是PROC未能干净利落地完成。尝试将SET @error_code = 0移到EXEC @default_dt = uf_get_default_date上方?

修改

确认,@ Damien的观点是正确的

SqlParameter error = new SqlParameter("@error_code", 0);

实际上是打电话给这个人:

public SqlParameter(string parameterName, SqlDbType dbType)

SqlParameter error = new SqlParameter("@error_code", 1234);

来电

public SqlParameter(string parameterName, object value)

原因:0 is implicitly castable to enum.

答案 1 :(得分:1)

当前的两个答案都略有不正确,因为它们基于为error对象调用的构造函数是(string,object)的假设。不是这种情况。文字0可以转换为任何枚举类型 1 ,并且这种转换优先于转换为object。所以被调用的构造函数是(string,SqlDbType)构造函数。

因此,类型设置为BigInt,因为这是SqlDbType枚举的0值,Value为空,因为您没有尝试设置的代码价值。

SqlParameter error = new SqlParameter("@error_code", (object)0);

应该使它选择正确的过载。


演示:

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");
        }
    }
}

打印:

SqlDbType
Object
Object
Object

1 C# Language specification, version 5第1.10节(即仅在介绍中的语言,未深入埋藏在语言法律位中) :

  

为了使枚举类型的默认值易于使用,文字0隐式转换为任何枚举类型。因此,允许以下内容。

Color c = 0;

我也认为这很重要,可以在MSDN上的语言参考中找到,但还没有找到明确的来源。

答案 2 :(得分:0)

嗯,看起来最可行的方法是使用this overload

SqlParameter error = new SqlParameter("@error_code", SqlDBType.Int);
error.Value = 0;

你正在使用的重载需要一个object作为参数,由于某种我无法理解的原因,它没有选择正确的类型。