在 c# 上检索存储过程的结果

本文关键字:结果 存储过程 检索 | 更新日期: 2023-09-27 18:31:12

>我有一个选择并返回年份列表的存储过程。在sql服务器中,我这样称呼它:

DECLARE @return_value int
EXEC    @return_value = [dbo].[TestName]
        @del= 0
SELECT  'Return Value' = @return_value

为了接收列表。

我的 SP 如下所示:

USE [TestTable]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[TestName] (@delvarchar(7))
AS
BEGIN
                    SELECT   YEAR(  [added]) AS year FROM [MyTable]

                    GROUP BY  YEAR(  [added]) 
                    ORDER BY  YEAR(  [added])  DESC
END

不过,我想从 c# 中做同样的事情,并在列表中传递值。

我正在尝试的是:

using (var conn = new SqlConnection(constr))
using (var command = new SqlCommand("TestName", conn)
{
   CommandType = CommandType.StoredProcedure
})
{
   command.Parameters.AddWithValue("@del", del);
   SqlParameter retval = command.Parameters.Add("@return_value", SqlDbType.VarChar);
   retval.Direction = ParameterDirection.ReturnValue;
   conn.Open();
   command.ExecuteNonQuery();
   int retunvalue = (int)command.Parameters["@return_value"].Value;
   conn.Close();
   return retunvalue;
}

但这不会返回任何值,而是只返回0。我做错了什么,如何按照指定的变量获取列表?

按照约翰汉纳的建议编辑代码,我有这样的东西:

        public List<string> getYears(string constr, int del)
        {
            using (var conn = new SqlConnection(constr))
            using (var command = new SqlCommand("TestName", conn)
            {
                CommandType = CommandType.StoredProcedure
            })
            {
                command.Parameters.AddWithValue("@del", del);
                List<string> retunvalue = new List<string>();
                conn.Open();
                SqlDataReader reader;
                reader = command.ExecuteReader();
                conn.Close();
                return retunvalue;
            }
        }

通过添加断点以探索reader我看到它只包含错误:

Depth = '(reader).Depth' threw an exception of type 'System.InvalidOperationException'

至于克里希纳的回答,dtList是空的,计数为0,我不知道如何实施巴德洪的建议。

在 c# 上检索存储过程的结果

之所以

这样称呼ExecuteNonQuery(),是因为它用于不查询数据的东西。返回0是命令更改的行数。

改用ExecuteReader(),您将获得一个SqlDataReader对象,您可以调用该对象Read()在行之间移动,然后检查每个行的详细信息。

如果要将其返回到另一种方法,请使用ExecuteReader(CommandBehavior.CloseConnection),然后在完成后Close()Dispose()连接,Close()Dispose()读取器,这将关闭连接。

如果您只有一行包含一列(或者由于某种原因只关心第一行的第一列,即使有更多),那么ExecuteScalar()是获取该单个值的便捷方法。

您不应该使用 ExecuteNonQuery,而应该使用 ExecuteDataSet,如下所示:

public List<DSM_DocPropIdentify> GetDocPropIdentify(string docPropIdentifyID, string action, out string errorNumber)
    {
        errorNumber = string.Empty;
        List<DSM_DocPropIdentify> docPropIdentifyList = new List<DSM_DocPropIdentify>();
        DatabaseProviderFactory factory = new DatabaseProviderFactory();
        SqlDatabase db = factory.CreateDefault() as SqlDatabase;
        using (DbCommand dbCommandWrapper = db.GetStoredProcCommand("GetDocPropIdentify"))
        {
            // Set parameters 
            db.AddInParameter(dbCommandWrapper, "@DocPropIdentifyID", SqlDbType.VarChar, docPropIdentifyID);
            db.AddOutParameter(dbCommandWrapper, spStatusParam, DbType.String, 10);
            // Execute SP.
            DataSet ds = db.ExecuteDataSet(dbCommandWrapper);
            if (!db.GetParameterValue(dbCommandWrapper, spStatusParam).IsNullOrZero())
            {
                // Get the error number, if error occurred.
                errorNumber = db.GetParameterValue(dbCommandWrapper, spStatusParam).PrefixErrorCode();
            }
            else
            {
                if (ds.Tables[0].Rows.Count > 0)
                {
                    DataTable dt1 = ds.Tables[0];
                    docPropIdentifyList = dt1.AsEnumerable().Select(reader => new DSM_DocPropIdentify
                    {
                        DocPropIdentifyID = reader.GetString("DocPropIdentifyID"),
                        DocPropertyID = reader.GetString("DocPropertyID"),
                        DocCategoryID = reader.GetString("DocCategoryID"),
                        DocTypeID = reader.GetString("DocTypeID"),
                        OwnerID = reader.GetString("OwnerID"),
                        IdentificationCode = reader.GetString("IdentificationCode"),
                        IdentificationSL = reader.GetString("IdentificationSL"),
                        AttributeGroup = reader.GetString("AttributeGroup"),
                        IdentificationAttribute = reader.GetString("IdentificationAttribute"),
                        IsRequired = reader.GetInt16("IsRequired"),
                        IsAuto = reader.GetInt16("IsAuto"),
                        SetOn = reader.GetString("SetOn"),
                        SetBy = reader.GetString("SetBy"),
                        ModifiedOn = reader.GetString("ModifiedOn"),
                        ModifiedBy = reader.GetString("ModifiedBy"),
                        Status = reader.GetInt32("Status"),
                        Remarks = reader.GetString("Remarks")
                    }).ToList();
                }
            }
        }
        return docPropIdentifyList;
    }

是 dbo。测试名称返回一个表或一个值。如果这返回一个表,那么你必须执行DataAdapter或执行DataReader。您应该替换上述声明如

DataTable dtList=new DataTable();
SqlDataAdapter adapter=new SqlDataAdapter();
adapter.SelectCommand=command;
adapter.Fill(dtList);

然后,您可以循环访问数据表并将其添加到列表中

List<Object> listObj=new List<Object>();
foreach(var rows in dtList.Rows)
{
    listObj.Add(rows["Column_name"]);
}

我分析了您的查询,发现该声明

DECLARE @return_value int
EXEC    @return_value = [dbo].[TestName]
        @del= 0
SELECT  'Return Value' = @return_value

返回多个表。您可以删除多余的最后一个语句。

SELECT  'Return Value' = @return_value

数据表现在将填充值。

让我知道这是否有效。