在 Dapper 中执行带参数的存储过程

Posted

技术标签:

【中文标题】在 Dapper 中执行带参数的存储过程【英文标题】:Execute stored procedure w/parameters in Dapper 【发布时间】:2014-03-03 03:13:57 【问题描述】:

我正在使用Dapper(感谢Sam,伟大的项目。)带有 DAL 的微型 ORM,由于某种原因,我无法使用输入参数执行存储过程。

在示例服务中,我有以下代码:

public void GetSomething(int somethingId)

    IRepository<Something, SomethingEnum> repository = UnitOfWork.GetRepository<Something, SomethingEnum>();

    var param = new DynamicParameters();
    param.Add("@somethingId", dbType: DbType.Int32, value:somethingId, direction: ParameterDirection.Input);

    var result = repository.Exec<Something>(SomethingEnum.spMyStoredProcedure, param);

    ...


当触发存储过程的执行时,会抛出一个 SqlException,说明我需要提供 'somethingId'

过程或函数“spMyStoredProcedure”需要参数“@somethingId”,但未提供。

我的DAL是基于Pencroff的这个github项目类似的。

我错过了什么吗?

更新:我实际上是通过 SomethingEnum 传递 commandType:

 public class SomethingEnum : EnumBase<SomethingEnum, string>
 
    public static readonly SomethingEnum spMyStoredProcedure = new SomethingEnum("spMyStoredProcedure", "[dbo].[spMyStoredProcedure]", CommandType.StoredProcedure);

    public SomethingEnum(string Name, string EnumValue, CommandType? cmdType): base(Name, EnumValue, cmdType)
    
    

【问题讨论】:

【参考方案1】:

您需要告诉它命令类型:确保在 dapper 调用中有 commandType: CommandType.StoredProcedure。否则,它只是执行 text 命令:

spMyStoredProcedure

(在环境上下文中带有一些未使用的参数)。这是合法的 TSQL,并尝试在不传递参数的情况下调用 spMyStoredProcedure - 就像将 spMyStoredProcedure 放入 SSMS 并按 f5 一样。

另外,如果你的参数是固定的,我实际上建议只使用:

var param = new  somethingId ;

甚至完全内联:

var result = repository.Exec<Something>(SomethingEnum.spMyStoredProcedure,
    new  somethingId , commandType: CommandType.StoredProcedure);

(注意:如果您的 Exec&lt;T&gt; 方法只处理存储过程,您可以将 commandType 内部移动到方法中 - 或者您可以将其设为默认为 CommandType.StoredProcedure 的可选参数)

【讨论】:

嗨,马克,感谢您的回复。我实际上是在SomethingEnum 上传递commandType。这个问题在某种程度上与我在 DynamicParameters 上的 DAL 有关。如果我内联执行它,它就可以工作。 @antao 好吧,Exec&lt;T&gt; 看起来不像是一种简洁的方法。你能说明这实际上变成了一个简洁的调用吗? 我实际上已经使用了这个实现:github.com/Pencroff/Dapper-DAL/blob/master/Dapper-DAL/… 不知何故,我的服务中有一个对 DynamicParameters 类的错误引用,并且存储库没有很好地处理这个事实。正确设置参考,一切正常。问题可以关闭。 (编译器(几乎)永远不会出错!)谢谢! @MarcGravell 我在 dapper 中使用存储过程来插入而不是发送单个参数我在参数中传递一个类的对象【参考方案2】:
var queryParameters = new DynamicParameters();
queryParameters.Add("@parameter1", valueOfparameter1);
queryParameters.Add("@parameter2", valueOfparameter2);

await db.QueryAsync<YourReturnType>(
    "NameOfStoredProcedure",
    queryParameters,
    commandType: CommandType.StoredProcedure)

【讨论】:

【参考方案3】:

因为这对我来说是最好的结果,但是没有解决带有表值参数的 ExecuteNonQuery 的答案,这里是代码:

var queryParameters = new DynamicParameters();
queryParameters.Add("@Param0", datatable0.AsTableValuedParameter());
queryParameters.Add("@Param1", datatable1.AsTableValuedParameter());
var result = await ExecuteStoredProc("usp_InsertUpdateTest", queryParameters);

private async Task<Result<int>> ExecuteStoredProc(string sqlStatement, DynamicParameters parameters)
    
        try
        
            using (SqlConnection conn = new SqlConnection(connectionString))
            
                await conn.OpenAsync();
                var affectedRows = await conn.ExecuteAsync(
                    sql: sqlStatement,
                    param: parameters,
                    commandType: CommandType.StoredProcedure);
                return Result.Ok(affectedRows);
            
        
        catch (Exception e)
        
            //do logging
            return Result.Fail<int>(e.Message);
        
    

【讨论】:

【参考方案4】:

您需要对其进行扩展以支持出站参数和返回结果,但它包含用于创建 Dapper 动态参数的部分。

internal static bool ExecuteProc(string sql, List<SqlParameter> paramList = null)

    try
    
        using (SqlConnection conn = new SqlConnection (GetConnectionString()))
                            
           DynamicParameters dp = new DynamicParameters();
           if(paramList != null)
               foreach (SqlParameter sp in paramList)
                   dp.Add(sp.ParameterName, sp.SqlValue, sp.DbType);
           conn.Open();
           return conn.Execute(sql, dp, commandType: CommandType.StoredProcedure) > 0;
        
    
    catch (Exception e)
    
        //do logging
        return false;
    

【讨论】:

这个方法的返回类型有点混乱,如果存储过程调用返回的代码大于0,则返回true。据我所知,存储过程返回代码通常用于表示程序成功,其中 0 表示 OK,> 0 表示不OK。使用此代码,如果存储过程返回 1,表明调用不正常,则 C# 方法返回 true,我将其解释为调用成功。 @Klicker,这个 .Execute 函数返回受影响的行数作为输出。【参考方案5】:

这对我有用。请注意,执行此操作的方法是异步的,因此需要等待和 QueryAsync。另请注意,创建了一个匿名类型以方便发送“Id”参数。

await dbConnection.QueryAsync<Something>("StoredProcedureNameGoesHere @Id", new  Id = id );

【讨论】:

以上是关于在 Dapper 中执行带参数的存储过程的主要内容,如果未能解决你的问题,请参考以下文章

C# Dapper缓存问题?

SQL Server 如何执行 带参数的 存储过程

使用没有字母参数的 Postgresql 的 Dapper 存储过程

Dapper 多参数存储过程查询不会从数据库返回任何内容

怎样在Delphi中实现在运行中实现带参数的存储过程?

Dapper 执行存储过程引发关于多映射的 ArgumentException