使用存储过程从Dapper.net查询返回值

时间:2013-01-09 21:46:04

标签: c# sql-server dapper

我正在尝试调用存储过程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支持完全存储的过程:

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

6 个答案:

答案 0 :(得分:6)

怀疑(未经测试),这与命名参数的方式完全不匹配;尝试(请注意已删除的@):

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

答案 1 :(得分:1)

您可以阅读以下值

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

答案 2 :(得分:1)

使用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;
    }

我在我的数据库中使用约定,即存储过程的名称是类型名称,后跟&#34; _s&#34; for select,&#34; _c&#34;对于插入,&#34; _d&#34;删除和&#34; _u&#34;更新。

PS:我讨厌使用Dapper的DynamicParameters或任何其他要求您为通用存储库中的每个类使用不同插入或更新方法的设备。

答案 3 :(得分:0)

我在读取QueryMultiple的结果时遇到了类似的问题。第一次调用Read()返回正确的类型,第二次调用返回DapperRow。我发现使用了类型化的Read():

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

解决了我的问题。

答案 4 :(得分:0)

为了简单起见,我已经减少了这一点。我正在使用输出参数,因为这使我可以完全控制传回的数据类型。我可以将此方法用于任何其他场景,而不仅仅是插入。

存储过程:

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 :(得分:0)

DynamicParameters解决方案对我来说并不干净。最好使存储过程代码返回一个整数(选择1;)并使用dapper ExecuteScalar<int>("[sp_name]", params);