我正在尝试在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;
}
}
答案 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;