来自executenonquery的截断输出参数

时间:2016-07-04 11:06:51

标签: c# ado.net

我正在尝试在C#中实现ExecuteNonQuery。 当我在SQL中执行时,storedProcedure本身工作正常。它返回SubmissionId的GUID和SubmitSequence的文本'submit sequence'。但是在.net中,它返回一个字符作为SubmitSequence的输出

ALTER PROC [dbo].[test_SP]
(
    @FormId uniqueidentifier,
    @FormCode varchar(10),
    @FormTitle nvarchar(200),
    @User nvarchar(50),
    @Url nvarchar(255) = NULL,
    @Host nvarchar(50),
    @RemoteHost nvarchar(50) = NULL,
    @UserAgent nvarchar(255) = NULL, 
    @Referrer nvarchar(255) = NULL,
    @SubmissionId uniqueidentifier out,
    @SubmitSequence varchar(30) out
) AS

BEGIN 

SET @SubmissionId = newid();
set @SubmitSequence = 'submit sequence'

-- INSERT Query
SELECT 
    @SubmissionId as SubmissionId,  @SubmitSequence  as SubmitSequence
END 

但是在.net中,我获得了SubmissionId的GUID(这是正确的)和SubmitSequence的文本'。

public SubmissionHeaderDTO GetRefNo()
        {
            var inPrms = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase)
                            {
                                {"FormId", Guid.NewGuid()},
                                {"FormCode", "TST"},
                                {"FormTitle", "Test form"},
                                {"User", "test"},
                                {"Host", "iisserver"}                               
                            };
            var outPrms = new Dictionary<string, object>(StringComparer.InvariantCultureIgnoreCase) { 
                            { "SubmissionId", Guid.NewGuid() },
                            { "SubmitSequence", "two"}
                            };
            var result = DBHelper.ExecSP(Constants.SPNames.SubmissionHeaderInsert, inPrms, outPrms);
            SubmissionHeaderDTO refNo = DictionaryToObject<SubmissionHeaderDTO>(result);
            return refNo;
        }

DBHelper.cs

public static Dictionary<string, object> ExecSP(string sp, Dictionary<string, object> paramIn, Dictionary<string, object> paramOut)
        {
            var dbAccess = new DBAccess();
            var results = dbAccess.ExecuteQuery(sp, paramIn, paramOut);
            return results;
        }

DBAccess.cs

public class DBAccess
    {
        public Dictionary<string, object> ExecuteQuery(string storedProcedure, Dictionary<string, object> parameters,
                                          Dictionary<string, object> outParameters)
        {

            using (var sqlConn = new SqlConnection(Configuration.DBConnection))
            {
                sqlConn.Open();
                using(var transaction = sqlConn.BeginTransaction("Results"))
                {
                    using(var sqlcmd = new SqlCommand(storedProcedure, sqlConn, transaction))
                    {
                        sqlcmd.CommandType = CommandType.StoredProcedure;
                        foreach(var kv in parameters)
                        {
                            sqlcmd.Parameters.AddWithValue(kv.Key, kv.Value);
                        }
                        foreach(var kv in outParameters)
                        {
                            sqlcmd.Parameters.AddWithValue(kv.Key, kv.Value).Direction = ParameterDirection.Output;
                        }

                        try
                        {
                            sqlcmd.ExecuteNonQuery();
                            var result = GetOutputParameters(sqlcmd.Parameters);
                            transaction.Commit();
                            return result;
                        }
                        catch(Exception)
                        {
                            transaction.Rollback();
                            throw;
                        }
                    }
                }
            }

        }

        private Dictionary<string, object> GetOutputParameters(SqlParameterCollection paramCollection)
        {
            var returnParameters = new Dictionary<string, object>();
            foreach (SqlParameter par in paramCollection)
            {
                if ((par.Direction == ParameterDirection.Output) || (par.Direction == ParameterDirection.ReturnValue))
                {
                    returnParameters.Add(par.ParameterName, par.Value);
                }
            }
            return returnParameters;
        }
    }

1 个答案:

答案 0 :(得分:1)

我将您的代码放入我自己的解决方案中并重新创建问题。您遇到了实际上永远不会做AddWithValue的原因之一。由于您要添加通用object,因此无法推断sql参数应该是什么数据类型。如果您在ExecuteNonQuery之前中断并检查参数列表,您将看到它被定义为NVARCHAR且没有长度。所以默认情况下长度为1。 您需要使用真实SqlDbType构建sql参数,并且应使用Value属性而不是AddWithValue来设置它们。

  

更新

要开始动态查询参数元数据,请查看此内容。请注意,您还有更多工作要做,例如将sql类型映射到SqlDbType

DECLARE @spName sysname;
SET @spName = 'test_SP';

DECLARE @objId int;
SELECT @objId = ISNULL([object_id], 0) FROM sys.procedures WHERE [name] = @spName;

SELECT p.[name], p.[system_type_id], t.[name], p.[max_length], p.[precision], 
    p.[scale], p.[is_output], p.[is_nullable]
FROM sys.parameters p
INNER JOIN sys.systypes t
    ON p.[system_type_id] = t.[xtype]
WHERE [object_id] = @objId;

enter image description here