SQLDataReader 在 ExecuteReader 之后读取为空

Posted

技术标签:

【中文标题】SQLDataReader 在 ExecuteReader 之后读取为空【英文标题】:SQLDataReader with an empty Read after ExecuteReader 【发布时间】:2014-05-26 11:44:44 【问题描述】:

请帮助纠正我的想法,我怀疑这要么是一个明显的错误,要么是对如何从存储过程中读取的误解。

我试图让 c# 调用存储过程并返回多行。如果我删除阅读器并使用

,它适用于具有单个实例的 ID
res = cmd.ExecuteNonQuery();

但在下面的代码中,while 部分只是被跳过了,我不明白为什么。我一直在玩代码并且没有任何运气。字段计数为零但表中有数据?

using (SqlConnection conn = new SqlConnection(connectionString))

    conn.Open();

    try
    
        using (SqlCommand cmd = new SqlCommand("dbo.ReadFromArchive", conn))
        
            cmd.CommandTimeout = 1000; //This should be the max timeout.
            cmd.CommandType = System.Data.CommandType.StoredProcedure;

            cmd.Parameters.Add("@ArchiveID", SqlDbType.Char).Value = AD.ArchiveID;

            cmd.Parameters.Add("@DocsKEY", SqlDbType.Char, 36).Direction = ParameterDirection.Output;
            cmd.Parameters.Add("@DocsDateKey", SqlDbType.DateTime).Direction = ParameterDirection.Output;
            cmd.Parameters.Add("@DocumentType", SqlDbType.VarChar, 100).Direction = ParameterDirection.Output;                  
            cmd.Parameters.Add("@OperationType", SqlDbType.VarChar, 30).Direction = ParameterDirection.Output;                   

            try
                                                                    
                SqlDataReader reader = cmd.ExecuteReader();
                while (reader.Read())
                
                    AD.AddDocKey((string)cmd.Parameters["@DocsKEY"].Value);
                    AD.AddDateKey((DateTime)cmd.Parameters["@DocsDateKey"].Value);
                    AD.AddDocument((string)cmd.Parameters["@DocumentType"].Value);
                    AD.AddOpType((string)cmd.Parameters["@OperationType"].Value);
                

                AD.RTKD = res;
                AD.RTMSG = "";
            
            catch (Exception ex)
            
                AD.RTMSG = ex.ToString();
                Logger.LogError("1. Error with executing dbo.ReadFromArchive Stored Procedure", ex);
            
        
        conn.Close();
    

    catch (Exception ex)
    
        AD.RTMSG = ex.ToString();
        Logger.LogError("Error setting up dbo.ReadFromArchive Stored Procedure :", ex);
    


return AD;

存储过程

ALTER PROCEDURE [dbo].[ReadFromArchive]
(

@ArchiveID      CHAR(36)        ,
@DocsKEY        CHAR(36)        OUT,
@DocsDateKey    DATETIME        OUT,
@DocumentType   VARCHAR(100)    OUT,
@OperationType  VARCHAR(30)     OUT

)
AS
BEGIN

Select @DocsKEY         = DocsKEY       from     dbo.ArchiveData where  ArchiveID = @ArchiveID          
Select @DocsDateKey     = DocsDateKey   from     dbo.ArchiveData where  ArchiveID = @ArchiveID              
Select @DocumentType    = DocumentType  from     dbo.ArchiveData where  ArchiveID = @ArchiveID 
Select @OperationType   = OperationType from     dbo.ArchiveData where  ArchiveID = @ArchiveID 

END

当我在没有存储过程的情况下直接查询 SQL 时,我给它的键(ArchiveID)返回两个单独的值。如果我删除阅读器,我会毫无问题地得到一个值。现在我需要对其进行迭代,因为数据库的每个 ID 都会有很多值。

不会抛出任何错误,只是不会返回任何数据。我的理解是读者应该遍历每一行,为什么不呢?我该如何解决?

【问题讨论】:

为什么要四选一?相反,您可以将其放入表中并将其返回给 C# 可以修改SP吗?是否有任何其他组件/系统依赖它? 是的,您可以修改 SP 我是原作者,目前它只在代码中的其他地方使用。我需要返回一个,返回多个,并返回所有匹配两个参数的值。主键是两个参数 ArchiveID 和 DocumentType。 【参考方案1】:

你做错了,你没有从reader读取数据:

在while循环中应该是这样的:

AD.AddDocKey(reader["DocsKEY"].ToString());

更新

我没有注意到 Store Procedure 中的 OUT 参数。

这是Using a DataReader to Process the RETURN Value and OUTPUT Parameters 上的 MSDN 参考。

SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
reader.Close();

AD.AddDocKey((string)cmd.Parameters["@DocsKEY"].Value);
AD.AddDateKey((DateTime)cmd.Parameters["@DocsDateKey"].Value);
AD.AddDocument((string)cmd.Parameters["@DocumentType"].Value);
AD.AddOpType((string)cmd.Parameters["@OperationType"].Value);
AD.RTKD = res;
AD.RTMSG = "";

【讨论】:

没有。我没有注意到SP中的OUT参数。【参考方案2】:

修改你的SP

ALTER PROCEDURE [dbo].[ReadFromArchive]
(

@ArchiveID      CHAR(36)   

)
AS
BEGIN

Select DocsKEY, DocsDateKey,DocumentType   ,OperationType  from     dbo.ArchiveData where  ArchiveID = @ArchiveID   

END

然后您可以按如下方式获取 while 循环内的列

reader["reader"].ToString();

【讨论】:

@st4hoo 他是对的,不是吗?在带有out 参数的当前设置中,每个参数只返回一个值。 OP想要读取从SP返回的多行,这需要不同的设置,例如,参数变为列 如果数据库的每个 ID 有很多值,那么您不能将它们放入 @variable 中,可以吗? @Me.Name:也许他是对的。这取决于对以下问题的回答:“SP 修改可能吗?”。 @st4hoo 同意,但如果不同意,他对Now I need to make it iterate because the database will have many values per ID. 的查询在当前 sp 和修改代码以使用阅读器是多余的情况下是不可能的。 @JonathanP out 参数将返回一个值,这也体现在需要在读取值之前关闭阅读器:它们是最后一个返回值,而不是每个返回的行。尽管理论上可以连接这些值,在参数中返回这些值,然后在代码中再次拆分它们,但这需要更改存储过程,在这种情况下,恕我直言,遵循 Mohameds 示例并让存储过程返回要容易得多一个表格,可以在阅读器(或DataTable)中读取【参考方案3】:

在关闭SqlDataReader 之前,您无法获取输出参数值。这里是对应的KB。

【讨论】:

以上是关于SQLDataReader 在 ExecuteReader 之后读取为空的主要内容,如果未能解决你的问题,请参考以下文章

关于sqlDataReader未显示问题

如何从 SqlDataReader 获取列的表名

如何使用 SqlDataReader 在结构数组中存储多个值

使用 SqlDataReader

如何在 JavaScript 中使用 C# SQLDataReader 对象

SqlDataReader.GetValue 对几何列不成功