有谁能告诉我这个功能发生了什么?
在以下代码段中,user.Id = 0
,id.Value = 0
和id.SqlDbType = Int
..正如预期的那样user.Id
是一个int字段。
但是,error.Value = null
和error.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
的解吗 的
在ASP论坛上找到这个链接......显然你不能读取输出参数,直到你读完SqlDataReader的所有结果...对我来说非常不幸,因为我决定是否我想读基于输出参数的结果......
答案 0 :(得分:2)
对于输出和返回值参数,该值在SqlCommand
完成时设置
即。我不会依赖类型推断来隐式设置返回类型。 我会明确设置输出参数的类型:
var error = new SqlParameter("@error_code", SqlDbType.Int)
{
Direction = ParameterDirection.Output
};
修改强>
经过一些SqlParameter
的反思:
BigInt
很容易解释 - 它是默认的SqlDbType
,SqlParameter(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)
答案 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
作为参数,由于某种我无法理解的原因,它没有选择正确的类型。