Возвращаемые значения из запроса Dapper.net с хранимой процедурой

Я пытаюсь вызвать хранимую процедуру using Dapper.Net и получить возвращаемые значения.

p.Add("@INCIDENT_ID", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

var retResults = con.Execute("usp_GetIncidentID", p, commandType:CommandType.StoredProcedure);

int IncidentID = p.Get<int>("INCIDENT_ID"); 

Я пробовал пару разных вещей с направлением параметров и использовал "@INCIDENT_ID". Если вы пройдете через результаты, вы увидите, что правильные возвращаемые значения сходятся в значении retResults, но я не могу получить доступ к значениям так, как описано в документации, как показано ниже.

Сохраненные процедуры Dapper поддерживает полностью сохраненные procs:

var user = cnn.Query<User>("spGetUser", new {Id = 1}, 
    commandType: CommandType.StoredProcedure).First();}}}
If you want something more fancy, you can do:

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

cnn.Execute("spMagicProc", p, commandType: commandType.StoredProcedure); 

int b = p.Get<int>("@b");
int c = p.Get<int>("@c");   

Ответ 1

Вы можете прочитать значение ниже

var incidentId = retResults.ToList()[0].INCIDENT_ID; 

Ответ 2

Я подозреваю (непроверенный), что это просто несоответствие в том, как вы называете параметр; попробуйте (обратите внимание на удаленный @):

p.Add("INCIDENT_ID", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);

var retResults = con.Execute("usp_GetIncidentID", p, commandType:CommandType.StoredProcedure);

int IncidentID = p.Get<int>("INCIDENT_ID"); 

Ответ 3

У меня возникла аналогичная проблема с чтением результатов QueryMultiple. Первый вызов Read() вернул правильный тип, второй - DapperRow. Я обнаружил, что используя типизированную версию Read():

var lineExists = query.Read<int?>().FirstOrDefault() == 1;

решил мою проблему.

Ответ 4

Я упростил это для простоты. Я использую выходные параметры, потому что это дает мне полный контроль над типом данных, который передается обратно. Я мог бы использовать этот подход с любым другим сценарием, а не только с вставками.

Сохраненный Proc:

ALTER PROCEDURE User_Insert (
@EmailAddress nvarchar(255),
@Id bigint OUT
) AS
INSERT INTO User (
        [EmailAddress]
    ) VALUES (
        @EmailAddress
    )
    set @Id = SCOPE_IDENTITY()

Код репозитория:

var sql = "Execute User_Insert @EmailAddress, @Id = @Id OUTPUT";
var _params = new DynamicParameters();
_params.Add("EmailAddress", user.EmailAddress);
_params.Add("Id", dbType: DbType.Int64, direction: ParameterDirection.Output);

using (var connection = new SqlConnection(ConnectionString)) {
    connection.Open();
    using (var transaction = connection.BeginTransaction()) {
        var result = SqlMapper.Execute(connection, sql, param, transaction);
        transaction.Commit();
    }
}    
var id = _params.Get<long>("Id");

Ответ 5

Используя тестовую версию Dapper, я обнаружил, что это работает как шарм:

result = dbConnection.ExecuteScalar<int>(typeof(UCCCCException).Name + "_c",
                        obj, commandType: CommandType.StoredProcedure);

Я пишу общий для использования при вставке объектов любого типа в базу данных.

Хранимая процедура выглядит следующим образом:

ALTER PROCEDURE [dbo].[UCCCCException_c]
(
@Id int = null,
@ExceptionDate datetime = null,
@HResult int = 0,
@Message varchar(8000) = null,
@Source varchar(8000) = null,
@StackTrace varchar(8000) = null,
@Module varchar(8000) = null,
@Name varchar(8000) = null,
@created_at datetime = null,
@updated_at datetime = null,
@created_by int = null,
@updated_by int = null
,
@Creator varchar(255) = null,
@Updator varchar(255) = null
)
AS

-- SET NOCOUNT ON added to prevent extra result sets from
-- interfering with SELECT statements.
SET NOCOUNT ON;

Insert into dbo.uccccexceptions ( ExceptionDate, HResult, [Message], [Source], StackTrace, Module, Name)
                            values (
                                    coalesce(@ExceptionDate,getdate()),
                                    @HResult,
                                    @Message,
                                    @Source,
                                    @StackTrace,
                                    @Module,
                                    @Name
                                    )
                                    ;
select @@Identity;
go

Оговорки по этому поводу заключаются в том, что вы должны указать запись для каждого свойства в классе, который вы используете, даже если эти свойства не существуют в целевой таблице в качестве параметра хранимой процедуры. Это может раздражать, если у вас есть несколько полей, которые являются полями просмотра в ситуациях MVC.

Чтобы получить возвращаемое значение, вам просто нужно использовать Execute и убедитесь, что ваш последний оператор: Select @@Identity в хранимой процедуре.

Он отлично работает и позволяет мне написать общую команду вставки в моем репозитории следующим образом:

        public virtual int Insert(T obj)
    {
        int result = -2;
        if (!databaseOnline)
        {
            throw new Exception(HttpStatusCode.ServiceUnavailable.ToString());
        }
        if (obj != null)
        {
            try
            {
                using (IDbConnection dbConnection = ConnectionProvider.OpenConnection())
                {
                    dbConnection.Open();
                    result = dbConnection.ExecuteScalar<int>(typeof(T).Name + "_c",
                        obj, commandType: CommandType.StoredProcedure);
                }
            }
            catch (SqlException sqlex)
            {
                Logger.LogError(sqlex, false);
                throw;
            }
            catch (Exception ex)
            {
                Logger.LogError(ex);
                throw;
            }
        }
        return result;
    }

Я использую соглашение в моей базе данных, что имя хранимой процедуры - это имя типа, за которым следует "_s" для выбора "_c" для вставки, "_d" для удаления и "_u" для обновления.

PS: Ненавижу использование Dapper DynamicParameters или любого другого устройства, которое требует использования другого метода вставки или обновления для каждого из ваших классов в общем репозитории.

Ответ 6

Решение DynamicParameters не чисто для меня. Гораздо лучше сделать код хранимой процедуры возвращать целое число (выберите 1;) и использовать dapper ExecuteScalar<int>("[sp_name]", params);