1

Я создал хранимую процедуру, аналогичную этот упрощенный пример:Чтение SP с выходными параметрами и набором результатов в C#?

CREATE PROCEDURE dbo.sp_MyStoredProcedure 
    @Var1 INT OUTPUT, 
    @Var2 DECIMAL(10,2) OUTPUT 
AS 
BEGIN 
    SET NOCOUNT ON; 

    SELECT 
     @Var1 = COUNT(*), 
     @Var2 = SUM(TranAmount) 
    FROM 
     MyTable 

    SELECT * FROM MyTable 
END 

При попытке чтения значения из выходных переменных после того, как вызвать ExecuteReader() метод SqlCommand объекта, значения равны нулем.

string MyConnString = string.Empty; 
SqlConnection MyConn = new SqlConnection(MyConnString); 
SqlCommand MyCmd = new SqlCommand("sp_MyStoredProcedure", MyConn); 
MyCmd.CommandType = CommandType.StoredProcedure; 
MyCmd.Parameters.Add(new SqlParameter("@Var1", SqlDbType.Int)); 
MyCmd.Parameters.Add(new SqlParameter("@Var2", SqlDbType.Decimal); 
MyCmd.Parameters[0].Direction = ParameterDirection.Output; 
MyCmd.Parameters[1].Direction = ParameterDirection.Output; 
SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection); 
int Var1 = Convert.ToInt32(MyCmd.Parameters[0].Value); 
decimal Var1 = Convert.ToDecimal(MyCmd.Parameters[1].Value); 

Что я делаю неправильно?

ответ

10

Вам необходимо дочитать читателя до конца, выходные параметры находятся в конце потока TDS, и клиент не увидит их до тех пор, пока результирующий набор не будет потреблен.

Если у вас есть счет и сумма перед чтением набора результатов, вы должны отключить параметры OUTPUT. Просто создайте обычный результирующий набор с двумя значениями, которые вы заинтересованы в покупке набора результатов SELECT *. Затем прочитайте оба набора результатов в клиенте, используя SqlDataReader.NextResult().

Update

Вот что я имею в виду, имея два набора результатов:

CREATE PROCEDURE dbo.sp_MyStoredProcedure  
AS 
BEGIN  
    SET NOCOUNT ON;  
    SELECT COUNT(*) as cnt, SUM(TranAmount) as sum_ta 
    FROM MyTable 
    SELECT * FROM MyTable 
END 

и клиент:

string MyConnString = string.Empty; 
SqlConnection MyConn = new SqlConnection(MyConnString); 
SqlCommand MyCmd = new SqlCommand("sp_MyStoredProcedure", MyConn); 
MyCmd.CommandType = CommandType.StoredProcedure; 
using(SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection)) 
{ 
    while(dr.Read()) 
    { 
    count = dr["cnt"]; 
    sum = dr["sum_ta"]; 
    } 
    dr.NextResult(); 
    while(dr.Read()) 
    { 
    // process MyTable row here 
    } 
} 

Обратите внимание, что вы делаете не нужно сделать это, если ваш код C# не нуждается в значении выходных параметров перед употреблением данных rea производная Вы можете просто прочитать SqlDataReader до конца и , затем проверить выходные параметры, они будут установлены.

1

Как сказал Ремус, если вам это нужно в первую очередь, тогда вам нужно переадресовать запрос. Почему у вас нет двух отдельных процедур? Это было бы лучшим решением в абстрактной форме.

В противном случае, вы можете сделать два SQL заявления Int ситемы одной партии

SELECT COUNT(*) AS VAR1, SUM(TranAmount) AS VAR2 FROM MyTable 
SELECT * FROM MyTable 

Затем, когда вы звоните ExecuteReader

SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection); 
while (dr.read()) 
{ 
    var1 = dr["Var1"]; 
    var2 = dr["Var2"]; 
} 

dr.NextResult(); 

while (dr.read()) 
{ 
    // blah blah blah code 
}