【问题标题】:Passing Output parameters to stored procedure using dapper in c# code在 c# 代码中使用 dapper 将输出参数传递给存储过程
【发布时间】:2014-04-16 17:26:41
【问题描述】:

我有一个这种格式的存储过程

CREATE PROCEDURE SP_MYTESTpROC
    @VAR1 VARCHAR(10),
    @VAR2 VARCHAR(20),
    @BASEID INT ,
    @NEWID INT OUTPUT
As Begin
   INSERT INTO TABLE_NAME(username, firstname)
      select @VAR1, @VAR2 
      WHERE ID = @BASEID

   SET @NEWID = SCOPE_IDENTITY() AS INT
END

我正在使用 dapper 从 C# 代码调用这个存储过程。我的问题是:如何在使用 dapper 时将输出参数传递给存储过程?

【问题讨论】:

  • 旁注:您应该为您的存储过程使用sp_ 前缀。微软有reserved that prefix for its own use (see Naming Stored Procedures),你确实会在未来某个时候冒着名称冲突的风险。 It's also bad for your stored procedure performance。最好只是简单地避免 sp_ 并使用其他东西作为前缀 - 或者根本不使用前缀!
  • RE:sp_ 在 sproc 名称中,根据我之前对@Steve 提供的答案的评论进行了注释,这绝对适用于 MS SQL 服务器。
  • 以下不是dapper ... 对于那些感兴趣的人,我展示了一个 MySQL / c# Visual Studio 2015 工作示例HERE。这种情况是 IN 和 OUT 参数之一。焦点自然是OUT

标签: c# sql sql-server stored-procedures dapper


【解决方案1】:

只要搜索Test.cs 文件就可以找到这个例子

    public void TestProcSupport()
    {
        var p = new DynamicParameters();
        p.Add("a", 11);
        p.Add("b", dbType: DbType.Int32, direction: ParameterDirection.Output);
        p.Add("c", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
        connection.Execute(@"create proc #TestProc 
                         @a int,
                             @b int output
                             as 
                             begin
                                 set @b = 999
                                 select 1111
                                 return @a
                             end");
        connection.Query<int>("#TestProc", p, commandType: CommandType.StoredProcedure).First().IsEqualTo(1111);
        p.Get<int>("c").IsEqualTo(11);
        p.Get<int>("b").IsEqualTo(999);
    }

所以,我想你的 C# 代码可以写成

    public void InsertData()
    {
        var p = new DynamicParameters();
        p.Add("VAR1", "John");
        p.Add("VAR2", "McEnroe");
        p.Add("BASEID", 1);
        p.Add("NEWID", dbType: DbType.Int32, direction: ParameterDirection.Output);
        connection.Query<int>("SP_MYTESTpROC", p, commandType: CommandType.StoredProcedure);
        int newID =  p.Get<int>("NEWID");
    }

附带说明,不要使用 SP 作为存储过程的前缀。它是为系统定义的程序保留的,如果 Microsoft 决定使用相同的名称,您可能会遇到麻烦。尽管不太可能,但这是一种不好的做法,为什么要冒险?

【讨论】:

  • 嗨史蒂夫,我会试试这个,它看起来确实合理且全面。是的,我知道存储过程的命名约定,我打算使用的是spMyTestProc
  • 这很干净,但是我不得不将First() 更改为FirstOrDefault(),因为First() 不断返回sequence contains no elements
  • 可能你可以删除它(FirstOrDefault)。从示例复制/粘贴时,我忘记将其清除(首先)。 (在那个例子中是有原因的,因为他们有一个返回 @a not present in your sp)
  • 是的!我刚刚取出了 'FirstOrDefault() 并且它起作用了。
  • 如果 TestProc 正在执行插入并且您正在调用 .Execute 而不是 .Query,是否有办法批量处理 proc 调用并获取批量进行的每个调用的 out 参数并返回值?
【解决方案2】:

关于“ath”的建议:为避免反射,DynamicParmers.AddDynamicParams() 采用匿名对象,之后您可以像这样添加返回参数...

var param = new { A="a", B="b" };
var dynamicParameters = new DynamicParameters();
dynamicParameters.AddDynamicParams(parameters);
dynamicParameters.Add("return", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

现在在您的 dapper 调用中使用 dynamicParameters 对象,而不是匿名参数对象。

(如果愿意,您也可以对输出参数执行此操作)

【讨论】:

  • 我认为 AddDynamicParams(parameters) 应该是 param 而不是 parameters,但我不能只编辑它,因为它必须是 6 个字符。
【解决方案3】:

如果您总是有一个名为@id (@id = @id OUTPUT) 的 INTEGER 类型的 OUTPUT 参数,您可以创建一个这样的扩展方法,它允许您使用常规的 Dapper 语法传递 sql 字符串和一个 @ 987654324@对象:

using Dapper;
using System.Data;
using System.Data.SqlClient;

public static int ExecuteOutputParam
            (this IDbConnection conn, string sql, object args)
        {
            // Stored procedures with output parameter require
            // dynamic params. This assumes the OUTPUT parameter in the
            // SQL is an INTEGER named @id.
            var p = new DynamicParameters();
            p.Add("id", dbType: DbType.Int32, direction: ParameterDirection.Output);

            var properties = args.GetType().GetProperties();
            foreach (var prop in properties)
            {
                var key = prop.Name;
                var value = prop.GetValue(args);

                p.Add(key, value);
            }

            conn.Execute(sql, p);

            int id = p.Get<int>("id");
            return id;
        }

这使用反射来读取所有属性,但如果您可以承受这种惩罚,您就不必为每次调用都编写 DynamicParameters 的样板。

对于事务,在 SqlTransaction 上创建一个扩展方法,将其传递给 Execute,如下所示:

transaction.Connection.Execute(sql, p, transaction);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-30
    • 2011-07-22
    • 2011-07-21
    • 2016-04-05
    相关资源
    最近更新 更多