Передача выходных параметров хранимой процедуре с использованием dapper в коде С#

У меня есть хранимая процедура в этом формате

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. Мой вопрос: как передать в выходной параметр хранимую процедуру при использовании 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);
    }

Итак, я полагаю, что ваш код С# можно записать как

    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 решит использовать одно и то же имя. Хотя маловероятно, это плохая практика и почему риск?

Ответ 2

Если у вас всегда есть параметр OUTPUT типа INTEGER с именем @id (@id = @id OUTPUT), вы можете создать такой метод расширения, который позволит вам использовать обычный синтаксис Dapper передавая строку sql и anonymous объект:

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);

Ответ 3

В дополнение к предложению "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);

Теперь используйте объект dynamicParameters в вашем вызове dapper вместо анонимного объекта param.