从C#我在下面做:
SqlParameter[] Params= new SqlParameter[3];
Params[0] = new SqlParameter("SearchCode", strSearchCode); // strSearchCode is a string
Params[1] = new SqlParameter("@Error", 0);
Params[1].Direction = ParameterDirection.Output;
Params[2] = new SqlParameter("@OutputCode", "");
Params[2].Direction = ParameterDirection.Output;
int i = SqlHelper.ExecuteNonQuery(connectionString, CommandType.StoredProcedure, "MySP", Params);
int intError = Convert.ToInt32(Params[1].Value);
string strOutputCode = Convert.ToString(Params[2].Value);
SqlHelper
是一个包含数据库查询方法的帮助器类,我只在这里发布调用中使用的那些:
public static int ExecuteNonQuery(string connectionString, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
if( connectionString == null || connectionString.Length == 0 ) throw new ArgumentNullException( "connectionString" );
// Create & open a SqlConnection, and dispose of it after we are done
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
// Call the overload that takes a connection in place of the connection string
return ExecuteNonQuery(connection, commandType, commandText, commandParameters);
}
}
public static int ExecuteNonQuery(SqlConnection connection, CommandType commandType, string commandText, params SqlParameter[] commandParameters)
{
if( connection == null ) throw new ArgumentNullException( "connection" );
// Create a command and prepare it for execution
SqlCommand cmd = new SqlCommand();
bool mustCloseConnection = false;
PrepareCommand(cmd, connection, (SqlTransaction)null, commandType, commandText, commandParameters, out mustCloseConnection );
// Finally, execute the command
int retval = cmd.ExecuteNonQuery();
// Detach the SqlParameters from the command object, so they can be used again
cmd.Parameters.Clear();
if( mustCloseConnection )
connection.Close();
return retval;
}
private static void PrepareCommand(SqlCommand command, SqlConnection connection, SqlTransaction transaction, CommandType commandType, string commandText, SqlParameter[] commandParameters, out bool mustCloseConnection )
{
if( command == null ) throw new ArgumentNullException( "command" );
if( commandText == null || commandText.Length == 0 ) throw new ArgumentNullException( "commandText" );
// If the provided connection is not open, we will open it
if (connection.State != ConnectionState.Open)
{
mustCloseConnection = true;
connection.Open();
}
else
{
mustCloseConnection = false;
}
// Associate the connection with the command
command.Connection = connection;
int timeOut = new System.Data.SqlClient.SqlConnectionStringBuilder(connection.ConnectionString).ConnectTimeout;
command.CommandTimeout = timeOut; //connection.ConnectionTimeout * 2;
// Set the command text (stored procedure name or SQL statement)
command.CommandText = commandText;
// If we were provided a transaction, assign it
if (transaction != null)
{
if( transaction.Connection == null ) throw new ArgumentException( "The transaction was rollbacked or commited, please provide an open transaction.", "transaction" );
command.Transaction = transaction;
}
// Set the command type
command.CommandType = commandType;
// Attach the command parameters if they are provided
if (commandParameters != null)
{
AttachParameters(command, commandParameters);
}
return;
}
private static void AttachParameters(SqlCommand command, SqlParameter[] commandParameters)
{
if( command == null ) throw new ArgumentNullException( "command" );
if( commandParameters != null )
{
foreach (SqlParameter p in commandParameters)
{
if( p != null )
{
// Check for derived output value with no value assigned
if ( ( p.Direction == ParameterDirection.InputOutput ||
p.Direction == ParameterDirection.Input ) &&
(p.Value == null))
{
p.Value = DBNull.Value;
}
command.Parameters.Add(p);
}
}
}
}
我的存储过程如下所示:
CREATE PROCEDURE [dbo].[MySP]
@SearchCode char(10),
@Error int OUTPUT,
@OutputCode char(50) OUTPUT
AS
DECLARE @Flag1 bit
DECLARE @IDate date
DECLARE @FDate date
DECLARE @TypeM tinyint
SELECT @OutputCode=SomeField FROM SearchTable WHERE FieldToSearch=@SearchCode
IF @@ROWCOUNT=0
begin
SET @Error=1
RETURN
end
SELECT @Flag1=Flag_1, @TypeM=MyType FROM AnotherTable WHERE Condition1=@OutputCode
IF @@ROWCOUNT=0
begin
SET @Error=2
RETURN
end
SELECT @IDate=InitDate, @FDate=FinalDate FROM AnotherTable2 WHERE Condition1=@OutputCode
IF @@ROWCOUNT=0
begin
SET @Error=3
RETURN
end
SELECT SomeField From AnotherTable3 WHERE Condition1=SomeCondition
IF @@ROWCOUNT=0
begin
SET @Error=4
RETURN
end
SELECT SomeField From AnotherTable4 WHERE Condition1=SomeCondition2
IF @@ROWCOUNT=0
begin
SET @Error=5
RETURN
end
SET @Error=0
我遇到的问题是当我这样做时,没有从C#代码中读取输出参数@OutputCode
:
string strOutputCode = Convert.ToString(Params[2].Value);
strOutputCode
包含"0"
。
如果是另一个输出参数:
int intError = Convert.ToInt32(Params[1].Value);
它返回ok,值为0
,因为存储过程的执行正在正确执行,并且在存储过程中没有满足@@ROWCOUNT=0
条件。
但是,如果我从SQL Server对同一个数据库启动存储过程:
DECLARE @OutputCode char(50)
DECLARE @Error int
DECLARE @SearchCode char(10) = '12003'
EXEC [dbo].[MySP] @SearchCode, @Error OUTPUT, @OutputCode OUTPUT
select @Error, @OutputCode
然后我得到@OutputCode
的正确值,该值是与"0"
不同的字符串。
我确保了商店程序中的第一个查询:
SELECT @OutputCode=SomeField FROM SearchTable WHERE FieldToSearch=@SearchCode
正在正确执行并返回一行一列,因此@OutputCode
被正确分配了值。
任何想法发生了什么?
答案 0 :(得分:1)
问题在于我没有指定输出参数的大小。由于我只是将值作为空字符串传递,因此默认情况下SQL Server的大小为1个字符而不是50个。因此,从C#我收到第一个字符,在这种情况下,是" 0&# 34。
指定输出参数的大小可以解决问题:
Params[2] = new SqlParameter();
Params[2].SqlDbType = System.Data.SqlDbType.NVarChar;
Params[2].ParameterName = "@OutputCode";
Params[2].Direction = System.Data.ParameterDirection.Output;
Params[2].Size = 50; // should be >=50
Params[2].Value = string.Empty;
备注强>: 如果输出参数小于50个字符,我们在末尾会收到空格,所以我们需要使用C#中的Trim函数删除末尾的空格。